Quick answer: WordPress cron (WP-Cron) runs scheduled tasks such as publishing future posts, checking updates, running backup plugins and sending digests. Unlike a classic server cron, WP-Cron usually wakes up when someone visits the site. On quiet sites, low-traffic periods or aggressive page caching, tasks pile up or fire late. Fixes include switching to a real system cron, reducing heavy hooks, resolving plugin conflicts and verifying that hosting does not block loopback requests.
How WP-Cron actually works
WordPress stores scheduled events in the database. On many installs, each front-end or admin request checks whether any event is due and, if so, spawns a request to wp-cron.php to process the queue. That design avoids needing server access on cheap shared hosting, but it couples scheduling to traffic.
Consequences:
- No visits can mean no cron runs
- A burst of visits can trigger overlapping work
- Full-page caches that never hit PHP can starve cron
- Long-running tasks can time out mid-job
Understanding this model explains most “my scheduled post published three hours late” tickets.
What depends on WordPress cron
Common consumers:
- Scheduled posts and pages
- Update checks
- Backup and security scanners
- Newsletter and CRM plugins
- Membership renewals and expiring content
- WooCommerce tasks (subscriptions, scheduled sales, holds)
- Custom plugin events your developer registered
If a feature says “daily” or “hourly,” it is often a cron event under the hood. Site WordPress monitoring should include noticing when those jobs stop, not only when the homepage is down.
Symptom checklist
Signs WP-Cron is unhealthy:
- Future posts stuck on “Scheduled” past their time
- Backups that claim to run nightly but show old timestamps
- Subscriptions or invoices that process in clumps
- Admin notices about loopback or REST failures
- High spikes of
wp-cron.phpin access logs
Reproduce on staging first when you can. Note the server time zone versus the WordPress time zone; mismatched zones cause “off by hours” confusion that looks like a cron bug.
Fix 1: Move to a real system cron
For any business site, this is the most reliable improvement.
- Disable the default traffic-triggered runner by adding
define('DISABLE_WP_CRON', true);towp-config.php - Add a system cron entry (or host panel cron) that requests
wp-cron.phpevery five minutes over HTTPS - Authenticate or restrict access to that URL as your host recommends
- Confirm events begin clearing on schedule even when the site has no visitors
Many managed WordPress hosts document this exact pattern. If your host blocks outbound or loopback calls, their support thread is part of the fix. Hosting quality matters here as much as plugin choice; see WordPress hosting.
Fix 2: Find the jammed event
Plugins such as WP Crontrol (or similar tools current in 2020) list scheduled events, callbacks and next run times. Look for:
- Events scheduled in the past that never complete
- Hooks from plugins you no longer use
- Hooks that run every minute on a site that cannot afford it
Delete orphaned events carefully after you uninstall abandoned plugins. Recreate schedules by revisiting plugin settings so they register fresh hooks.
Fix 3: Reduce heavy jobs
Cron is a queue, not a supercomputer. Problems appear when:
- A backup tries to dump a huge site during peak traffic
- A security plugin scans everything every few minutes
- A custom job processes thousands of rows in one request
Split work into batches, run heavy jobs off-peak and prefer host-level backups when appropriate. WordPress maintenance routines should include reviewing which plugins schedule what.
Fix 4: Caching and cron
Page caches that serve static HTML without loading WordPress can prevent the default WP-Cron trigger. That is another reason to use system cron. If you must keep traffic-based cron temporarily:
- Exclude
wp-cron.phpfrom cache - Ensure logged-in and cart paths still execute PHP when needed
- Do not block user agents that the cron runner needs
Object caching rarely replaces cron; it only speeds data access for jobs that do run.
Fix 5: Loopback and HTTP issues
WordPress often calls itself over HTTP to run cron. Failures happen when:
- DNS for the domain points elsewhere during migration
- SSL problems make loopback fail
- Security plugins block local requests
- The site URL / home URL settings are wrong
Check Settings, general URLs, and security allowlists. Temporary migration modes and basic auth on staging also interrupt cron; document that so editors do not expect scheduled posts to fire on locked staging.
Plugin conflicts and custom code
Badly written wp_schedule_event calls, missing clear schedules on deactivation, or fatal errors inside callbacks will stall the queue. Debug by:
- Disabling recently added plugins on a staging copy
- Enabling logging for fatal errors during a manual
wp-cron.phphit - Reviewing custom themes for cron registrations
Custom plugin work should register and deregister events cleanly; see discipline similar to other custom WordPress plugin development practices.
WooCommerce and membership specifics
Stores and membership sites feel cron pain faster because money is attached. After fixing the runner:
- Re-save WooCommerce settings that register schedules
- Verify Action Scheduler (used by modern WooCommerce) is not buried under failed actions
- Confirm subscription plugins show upcoming renewals at the right times
Test with a low-value product or staging stripe/test mode before declaring victory.
Prevention habits
- Prefer system cron on production
- Inventory scheduled events quarterly
- Avoid installing multiple plugins that all want to “optimise” or scan constantly
- Keep core, themes and plugins updated after staging tests
- Document the cron setup in your website documentation so the next developer does not “fix” DISABLE_WP_CRON without replacing it
Quiet brochure sites on full-page cache are the classic failure mode. High-traffic stores fail differently: overlapping jobs and timeouts. Same subsystem, different pressure.
Debugging step by step
When a scheduled post fails on production:
- Confirm WordPress timezone and server time
- Check whether
DISABLE_WP_CRONis set and whether system cron exists - Hit
wp-cron.phpmanually while watching error logs - List events and find the
publish_future_posthook or plugin equivalent - Temporarily switch to a default theme on staging if you suspect theme fatals
- Re-test with a post scheduled a few minutes ahead
For backup plugins, compare the plugin’s own log with server cron history. Many “cron failures” are really timeouts or disk quota problems during the job itself. Fixing the runner will not help if the backup has nowhere to write.
Communication with clients and editors
Editors experience cron as “WordPress did not publish my post.” Explain in plain language that the scheduler needs a reliable trigger, especially on cached sites. Put the system cron setup in the handover pack so future freelancers do not revert it. If you offer retainers, include a quarterly check of failed events alongside plugin updates.
FAQ
Is WP-Cron the same as Linux cron?
No. WP-Cron is WordPress’s internal scheduler. Linux cron is the server’s scheduler. You can use Linux cron to trigger WP-Cron reliably.
Will disabling WP-Cron stop scheduled posts?
Only if you disable it without adding another trigger. Always replace it with system cron.
Can I run cron every minute?
You can, but many sites do fine every five minutes. Very frequent runs can add load if jobs are heavy.
Why did cron break after I installed a firewall plugin?
Some firewalls block loopback or the user agent used to call wp-cron.php. Whitelist the cron request path.
Make schedules boring again
WordPress cron problems are usually architecture, not mystery. Give production a real system cron, clean stuck events, lighten heavy jobs and document the setup. If you want WordPress care that includes reliable scheduling and maintenance, see how we help businesses turn visitors into customers.