If you have ever wondered why your scheduled WordPress post went live 11 hours late, why your WooCommerce renewal emails show up Tuesday morning for Monday's renewal cycle, or why your weekly Mailchimp export "ran" but never landed, the answer is almost always the same: wp-cron. It is not really cron. It is a clever workaround that was fine in 2007 and breaks every time your traffic dips. Here is what wp-cron actually does, why it misses, and how to replace it with a real external scheduler in about 5 minutes.
If you just want the short version: drop define('DISABLE_WP_CRON', true) into wp-config.php, point Crontap at https://yoursite.com/wp-cron.php?doing_wp_cron=1 every 5 minutes (or every 1 minute on Crontap Pro), and walk away.
What wp-cron actually is
Open wp-config.php on any WordPress install and look for the constant DISABLE_WP_CRON. If it is not there, your site is using "wp-cron", which is the polite name for "fire scheduled tasks on the next page request that happens to come in within 60 seconds of when the task should have fired".
That is not cron. Real cron is a daemon that wakes up every minute and runs whatever is due. wp-cron has no daemon. It is a hook in wp-cron.php that fires when a visitor (or a search engine, or anyone hitting almost any URL on the site) loads a page. WordPress uses the request to check which scheduled events are overdue, then loops through and runs them inline before sending the response.
It works on a small blog where someone hits the homepage every few minutes. It misses everywhere else.
Why it misses
There are three reasons "scheduled" WordPress events are quietly going late or not running at all.
Pseudo-cron is tied to visitor traffic
If your store has zero visitors between 4am and 7am and your daily report is set for 5am, the report does not fire at 5am. It fires on whatever request comes in first after 5am, and not in any specific order relative to other overdue events. A 5am Monday digest on a site that gets its first visitor at 8:14 is already late by the time it runs.
If your site uses a CDN with a caching layer in front, this gets worse. WordPress only sees a request when the cache misses; long-cached pages do not tick wp-cron at all.
Shared hosting rarely gives you system cron
The "real" fix that WordPress's own Plugin Handbook on hooking WP-Cron into the system task scheduler recommends is to disable wp-cron and run a real cron job on the server that hits wp-cron.php every few minutes. The catch: most shared hosts (Bluehost, SiteGround, GoDaddy, Hostinger) either do not give you crontab access, lock cron behind their control panel with weird cadence buckets, or quietly run it themselves at 15-minute intervals you cannot change.
If you are on managed WordPress (Kinsta, WP Engine), you usually have a single crontab fixed at 15 minutes minimum. That is fine for "send the weekly newsletter" and bad for "process the every-minute import".
Every plugin registers its own wp-cron events
WooCommerce alone schedules dozens. Action Scheduler (the queue WooCommerce uses under the hood, see the WooCommerce Scheduled Actions docs) keeps adding actions as orders come in, subscriptions renew, coupons expire, and email digests queue up. Backups, security scans, ActiveCampaign syncs, Yoast, RankMath, every form plugin, every membership plugin: each adds its own scheduled events.
When wp-cron finally fires, it tries to clear the entire backlog inline on a single page request. If the backlog is large, the request times out, the page is slow, and only the first few events run. The rest wait for the next visitor.
Symptoms you are probably seeing
If any of these sound familiar, wp-cron is the prime suspect.
- Scheduled posts publish hours after their
post_date. - WooCommerce subscription renewal emails fire on a different day than the renewal.
- The weekly "Sales for last week" email shows up Tuesday lunchtime, not Monday morning.
- WP Crontrol shows a long list of overdue events that never seem to clear.
- The site visibly slows down for the first visitor of the day because wp-cron is draining a queue at them.
- Daily backups skip days when traffic is low.
For example, take a WordPress site running an inbox automation product that polls third-party APIs roughly every 1.1 minutes for its core fetcher loop. On wp-cron, "every 1.1 minutes" only happens if the site sees at least one request in every window. The first quiet stretch of the day, the queue stretches, and the polling silently slips behind. We have seen sites in this archetype go from "every 1.1 minutes" expected cadence to 15-minute and 30-minute gaps overnight before they switched to a real external trigger.
The documented fix (DISABLE_WP_CRON + external trigger)
This is the path WordPress's own docs prescribe. The code change is two lines.
- Open
wp-config.php(in the root of your WordPress install). - Above the line that says
/* That's all, stop editing! */, add:
define('DISABLE_WP_CRON', true);
- Save and deploy.
WordPress now does not auto-tick wp-cron on page loads. Scheduled events stop firing entirely until something else hits wp-cron.php.
The "something else" is the part shared hosting makes hard. The classic fix is a server crontab entry like:
*/5 * * * * curl -s https://yoursite.com/wp-cron.php?doing_wp_cron=1 >/dev/null 2>&1
If you have shell access on a real server, that line works. If you are on managed WordPress or shared hosting and you cannot edit the crontab, you need an external HTTP cron. That is the part Crontap solves.
Setting up Crontap to hit wp-cron.php
Total time, including the wp-config edit: about 5 minutes. The flow is the same for every WordPress install, whether you are on Hostinger, WP Engine, a Hetzner box, or a Kubernetes deploy.
- Edit
wp-config.php. Adddefine('DISABLE_WP_CRON', true);as shown above. Deploy. - Confirm wp-cron has stopped. Install WP Crontrol (free, well-maintained, the standard tool here). Open Tools, then Cron Events. You should see a list of scheduled events with "Next Run" timestamps that no longer change as visitors hit the site.
- Create a Crontap schedule. Head to Crontap, sign up (free tier available, no credit card), and click Create schedule.
- URL. Paste
https://yoursite.com/wp-cron.php?doing_wp_cron=1. The query string is the same parameter WordPress's own internal request uses; it tells WordPress the request is a cron tick. - Method.
GETis fine. WordPress accepts both, butGETmatches WordPress core's own internal request shape. - Cadence. "Every 5 minutes" is the going default. If you need more, you can run every 1 minute on Crontap Pro. For a low-traffic content site, every 15 minutes is plenty; for an active store with real-time renewals, go down to every minute.
- Timezone. Pick the IANA zone your store actually runs in, not UTC, not your own. If your customers are in Europe/London, set Europe/London. Crontap will handle DST automatically. WordPress itself stores
post_date_gmt, but the human-facing schedules (5am Monday digest, 9am US morning email) read the WordPress site timezone, so matching them in Crontap keeps the mental model honest. - Failure alerts. Add an integration: email / webhook (Slack / Discord / Telegram). Crontap fires on 4xx and 5xx with the response body and timing in the payload, so a Slack alert lands in your ops channel the moment
wp-cron.phpreturns a 500. - Press Perform test. Watch the response. A healthy wp-cron tick returns 200 with no body (or with a small text response, depending on your install).
Fix this in 60 seconds with Crontap. Free tier available. No credit card. Schedule your first job →
That is the whole setup. Scheduled posts now publish on time. WooCommerce subscription emails fire on the right day. Weekly digests show up at 5am, not 8:14am.
Verify with WP Crontrol or similar
Once Crontap is firing, open WP Crontrol again. The "Next Run" column should now show events ticking down on whatever cadence you set. If you have an event that says "Now" but never moves, it is a stuck event; click "Run Now" once to clear it, then watch the next cron tick from Crontap pick up the schedule.
Two sanity checks:
- Open the Activity tab in Crontap on the schedule. After the first 5 minutes you should see green 200s with sub-second response times.
- Tail your WordPress access logs (or check the host's). You should see one request to
/wp-cron.php?doing_wp_cron=1at the cadence you set, and no more drive-by ticks from random page loads (because wp-cron is disabled inline).
Per-minute WordPress work (the floor on Crontap Pro is 1 minute)
A small but real slice of WordPress sites need every-minute work: real-time API polling, every-minute imports, near-real-time alerting. wp-cron physically cannot do this; without traffic, the cadence is whatever the visitor pattern allows.
Crontap Pro goes down to every 1 minute, which is the floor. If you need sub-minute (every 30 seconds, every 10 seconds), Crontap is not the answer; you almost certainly want a worker process running an in-process scheduler at that point. For everything from every 1 minute up to monthly, Crontap is the right tool.
For honesty about the data: in our customer dataset across WordPress sites, we have seen 14 jobs running at or below minute cadence (historical extracted slice, pre-2026-04-27 product correction). The current product floor is 1 minute on Pro, so the every-minute portion of that cohort is fully reachable today; the sub-minute portion is not, and was not the right shape for an HTTP cron anyway.
What to do for WooCommerce specifically
WooCommerce has its own scheduling layer on top of wp-cron called Action Scheduler. It is a queue, not a clock. It still depends on wp-cron firing to drain the queue, which means every problem above applies to WooCommerce, plus a few extras: subscription renewals, coupon expirations, refund processing, abandoned cart emails. If your shop is the one losing renewals, the deep dive on the exact symptoms and the WooCommerce-specific fix is in WooCommerce cron not running: the traffic problem and the fix. The TL;DR is the same as this post: disable wp-cron, point Crontap at the queue, and Action Scheduler suddenly behaves.
For a UK restaurant on WordPress sending a weekly sales report at 5am Monday in Europe/London, Crontap is the difference between the report landing at 5am and the report landing whenever the first staff member opens the admin tab on Monday morning. The cadence is the same; the trigger is what changed.
FAQ
Will disabling wp-cron break anything?
No, as long as something is still hitting wp-cron.php on a cadence. The events themselves still register the same way; only the "fire on visitor traffic" part is removed. Most WordPress sites are unambiguously better with the visitor-tied behaviour off.
What cadence should I use?
Every 5 minutes is the safe default for most WordPress installs. Drop to every 1 minute on Crontap Pro if you have time-sensitive work (renewals, real-time imports, every-minute polling). Hourly is fine for content-only sites that just need scheduled posts to publish on time.
Do I need WP Crontrol?
Only for verification. WP Crontrol is the easiest way to see what events are scheduled and confirm they are running. After the first day of green Crontap fires, you can leave it active or remove it, your call.
What about cache plugins (WP Rocket, W3 Total Cache)?
They do not interfere. wp-cron.php bypasses the page cache because it is treated as an admin-side file. If you are using object cache (Redis, Memcached) for the database layer, that is a net positive: wp-cron events will run faster because the lookups are cached.
Will Crontap and the host's built-in 15-minute cron conflict?
No. wp-cron events are idempotent (each event runs once and is removed from the queue). If both Crontap and the host hit wp-cron.php, whichever arrives first runs the event; the other request finds an empty queue and returns. There is no harm, only a tiny extra request.
Do I need this for a hobby blog?
If you have steady traffic and wp-cron is firing on time, no. wp-cron's traffic-tied behaviour is fine for high-traffic sites. The pain shows up when traffic is unpredictable, when the site is global with timezone-sensitive schedules, or when WooCommerce is involved.
References
- WordPress Plugin Handbook: Hooking WP-Cron into the System Task Scheduler
- WooCommerce: Scheduled Actions
- WordPress.org: WP Crontrol plugin
Related on Crontap
- Cron jobs for WordPress, the platform spoke. The WordPress-specific guide to running scheduled work without wp-cron.
- WooCommerce cron not running: the fix. The WooCommerce sibling post with Action Scheduler specifics.
- Cron syntax cheat sheet. Every cron expression you will reach for, with examples.
