Scheduled actions stopped running
When the background queue stalls, sales never end, emails never send and stock never syncs — while the storefront looks perfectly healthy.
The symptom
Nothing looks broken. Pages load, orders come in, the admin is responsive. But a scheduled sale that should have ended last month is still running, a follow-up email never arrived, and an integration that syncs stock every hour last synced in July.
In WooCommerce → Status → Scheduled Actions there is a Past-due tab, and it has entries in it. Sometimes thousands.
Often the first sign is a notice at the top of the admin, in exactly these words:
Action Scheduler: 848 past-due actions found; something may be wrong. Read documentation »
Only the number changes (with a single action it reads 1 past-due action found). By default WooCommerce shows the notice once at least one action is more than a day overdue.
What it costs
WordPress has no real scheduler. It has WP-Cron, which only runs when somebody visits the site, and WooCommerce layers Action Scheduler on top of it for anything that must survive a restart. Almost everything that happens later in a store rides on that queue:
- Scheduled sales never end.
wc_scheduled_salesis a cron job. If it does not run, a product keeps selling at the promotional price indefinitely — this is the direct cause behind a sale that will not stop. - Emails do not send. Order follow-ups, abandoned cart reminders, review requests, renewal notices — all queued.
- Stock and price syncs stall. ERP, marketplace and feed integrations queue their work; the catalogue silently drifts from reality.
- Subscription renewals do not charge. On stores that sell subscriptions this is revenue that simply never bills.
The reason this survives for months is that it produces no error anywhere a human looks. There is no white screen. There is just a store that quietly stops doing anything it was told to do later.
How to check it yourself
Three angles, from cheapest to most complete.
1. The screen WooCommerce already gives you. Go to WooCommerce → Status → Scheduled Actions and open the Past-due tab. A handful of items a few minutes old is normal on a quiet site. Hundreds, or anything hours old, is not.
2. From WP-CLI:
wp cron event list --fields=hook,next_run_relative --format=table
wp action-scheduler status
wp cron event list marks overdue events as now or with a negative relative time. If everything
is overdue, WP-Cron itself is not firing.
3. Check whether WP-Cron was switched off and never replaced. In wp-config.php:
grep -n "DISABLE_WP_CRON" wp-config.php
define( 'DISABLE_WP_CRON', true ); is not a bug by itself — it is the recommended setup on busy
stores. It becomes a bug when nobody ever added the real system cron that was supposed to replace
it. Confirm the replacement exists:
crontab -l | grep wp-cron
How to fix it
-
Give the site a real scheduler. Either through your host’s cron panel, or a crontab entry every five minutes:
*/5 * * * * curl -s https://example.com/wp-cron.php?doing_wp_cron >/dev/null 2>&1Then set
DISABLE_WP_CRONtotrue, so visitor requests stop trying to run the queue as well. -
Drain the backlog once, so you are not waiting for it to catch up on its own:
wp action-scheduler run --batch-size=50 -
Deal with what the backlog was hiding. A sale that should have ended three weeks ago does not fix itself when the queue restarts — some of those jobs have deadlines that already passed. Check prices before you assume the catch-up did the work.
-
Look at failed actions too, not only pending ones. A job that fails every run keeps the queue busy without ever completing.
When it is a false positive
- A brand-new store with nothing scheduled yet: no past-due actions, but also no evidence the queue works. Merchlint reports what it can see and says so, rather than guessing.
- Your host runs cron outside the site, in a way the database cannot show. If
DISABLE_WP_CRONis set and the queue is empty and recent actions completed, everything is fine — the finding only fires when actions are actually overdue. - A deliberately paused queue during a migration or a bulk import. Legitimate, and worth un-pausing before you forget.
How Merchlint finds it
Merchlint reads the action_scheduler_actions table for actions still in pending whose scheduled
time is in the past by more than the threshold, and reads the DISABLE_WP_CRON constant and the
timestamp of the most recently completed action. The finding shows how many actions are overdue,
how old the oldest one is, and whether DISABLE_WP_CRON is set — the three facts you need to tell
“cron is off” apart from “cron is on but drowning”.
Confidence: F — fact from the database. A scheduled time is either in the past or it is not.
This check moved into the free version on 20 August 2026, because it names the cause behind a whole class of other findings — including sales that will not end and stock that never updates. A report that lists the symptoms without naming that cause sends you fixing products one at a time.
Disagrees with what you see in your store? Write to us — we read every message. contact@merchlint.com