A wholesale distribution client needed WooCommerce to automatically chase unpaid orders with three professionally timed emails. The constraint was firm: no third-party plugins. I engineered the entire system from scratch — hooks, scheduler, HTML email templates, and admin UI included.
The client's WooCommerce store was losing revenue to unpaid orders with no follow-up mechanism. Every plugin solution was off the table — they needed a clean, custom-coded system they owned outright.
WooCommerce has no native payment chase system. Pending orders were expiring silently — no follow-up, no urgency, no revenue recovery process in place.
I used WooCommerce's already-bundled Action Scheduler — a production-grade background job queue — to schedule and fire all three reminder jobs with precision timing and zero plugin overhead.
Any developer can reach for a plugin. Building a custom automation from first principles — understanding WordPress hooks, leveraging WooCommerce internals, handling every edge case in code — that is engineering. The client now owns a leaner system with zero licensing costs, zero plugin conflicts, and complete control over the logic forever.
Each email escalates in urgency and tone — a friendly nudge at day 1, a firm notice at day 4, and a final void warning at day 6. All three are cancelled the instant the order is paid.
A polite, professionally branded reminder that an invoice is awaiting payment. Assumes the customer may have simply forgotten. Includes full invoice summary, amount due, issued date, and direct contact via email and WhatsApp.
Elevated urgency with a prominent "Action Required" badge. Introduces a dedicated resolution channel for customers experiencing payment difficulties — reducing genuine abandonment while applying the right pressure on intentional non-payers.
The final and most urgent message. Clearly states the invoice will be voided without immediate action and warns of account standing implications for repeat non-payment. No further automated emails are sent after this stage.
Every edge case is handled in code — re-pending orders, duplicate job runs, cancelled orders and admin testing all work flawlessly without any developer intervention after deployment.
WooCommerce fires the woocommerce_order_status_changed hook. The system detects the "pending" new status, clears any previous reminder flags to cleanly handle re-pending edge cases, then immediately schedules all three background jobs into Action Scheduler's queue.
Using WooCommerce's bundled Action Scheduler — the same engine WooCommerce uses internally for its own jobs — each reminder fires in an isolated background HTTP request. Completely independent of user page loads. No unreliable WP-Cron visitor-trigger dependency.
The moment a job fires, the dispatcher performs two checks: is the order still pending? Has this reminder already been sent? Only if both conditions pass does the email go out — eliminating duplicate sends even if Action Scheduler retries a job.
A second hook listener watches for any status transition away from pending. The moment an order becomes processing, on-hold, completed or cancelled, all three queued reminder actions are removed from the Action Scheduler queue via as_unschedule_action — immediately and automatically.
Each pending order's edit page displays a live status widget showing which reminders have fired (with exact timestamps) and which are queued (with countdown). Dedicated order action buttons allow any reminder to be manually triggered for QA testing without touching a line of code.
Core scheduling logic — the moment an order goes pending, three precisely timed background jobs are queued:
// Fires on every order status transition add_action( 'woocommerce_order_status_changed', 'schedule_reminder_emails', 10, 4 ); function schedule_reminder_emails( $order_id, $old_status, $new_status, $order ) { // Only act when transitioning TO pending if ( $new_status !== 'pending' ) return; // Clear any existing scheduled jobs + sent flags (handles re-pending edge case) cancel_reminder_emails( $order_id ); delete_post_meta( $order_id, '_reminder_1_sent' ); delete_post_meta( $order_id, '_reminder_2_sent' ); delete_post_meta( $order_id, '_reminder_3_sent' ); $args = [ 'order_id' => $order_id ]; // Queue Reminder 1 — fires 24 h after pending status is set as_schedule_single_action( time() + ( 24 * HOUR_IN_SECONDS ), 'reminder_email_1', $args ); // Queue Reminder 2 — fires 96 h (4 days) after pending status is set as_schedule_single_action( time() + ( 96 * HOUR_IN_SECONDS ), 'reminder_email_2', $args ); // Queue Reminder 3 — fires 144 h (6 days) after pending status is set as_schedule_single_action( time() + ( 144 * HOUR_IN_SECONDS ), 'reminder_email_3', $args ); }
No unnecessary dependencies. Every tool used is either native to WordPress, bundled with WooCommerce, or standard PHP — making this system maintenance-free and future-proof.
WooCommerce's production-grade background job processor. Battle-tested at millions of jobs — far more reliable than WP-Cron for time-sensitive email delivery.
Custom filter and action callbacks hooked to woocommerce_order_status_changed for real-time scheduling and instant job cancellation on payment.
Three fully custom HTML email templates — one per reminder stage — with correct urgency escalation, brand colours, and structured invoice detail layouts.
Idempotency guards stored as order post meta ensure no reminder is ever sent twice — even if Action Scheduler retries a failed job or the order re-enters pending.
Custom entries injected into the WooCommerce order action dropdown allow any reminder to be triggered manually for QA — no custom admin page required.
A status widget on every pending order page displays exactly which reminders have fired (with timestamps) and which are queued with time remaining.
A fully autonomous payment recovery system running silently in the background — 100% custom-built, zero ongoing maintenance, zero recurring costs, and complete code ownership.
Every pending order is now automatically chased at the right time with the right urgency — without any manual work from the client ever.
No licences to renew, no plugin update conflicts to manage, and no third-party servers ever handling sensitive customer order data.
Re-pending orders, duplicate job runs, simultaneous status changes — every scenario was anticipated and guarded against in the initial build, in code.
Three custom HTML email templates far beyond WooCommerce defaults — branded, responsive, with escalating urgency designed to convert at each stage.
"My client came with a hard constraint — no plugins, make it reliable, make it look professional. That's exactly the kind of engineering problem I enjoy. The result is a system that requires zero maintenance and will keep recovering revenue for their business indefinitely."
I specialise in custom WordPress, WooCommerce and PHP solutions built exactly to your business requirements — without the plugin bloat or recurring licence costs.