If you’ve ever had a scheduled post fail to publish, a backup job not run, or WooCommerce emails send late, you’ve already met the downside of WordPress’s default scheduling system. Replace WP-Cron with Real Cron and you’ll usually fix “missed schedule” headaches and reduce unnecessary overhead—especially on sites with either very low traffic (cron never triggers) or very high traffic (cron triggers too often).
WordPress uses something called WP-Cron, which is not a real server cron daemon. It’s a “pseudo-cron” that runs when someone visits your site. That design is convenient because it works on almost any hosting environment without you touching server settings—but it also means timing is tied to page loads, caching behavior, and sometimes blocked loopback requests.
In this guide, you’ll learn what WP-Cron is, why it misses schedules, and exactly how to disable it safely and run it on a real server schedule (system cron). I’ll also cover common pitfalls (like caching, 403 loopbacks, Cloudflare/WAF rules, and WooCommerce action scheduler backlogs) plus a quick testing checklist.
What WP-Cron is (and why it causes missed schedules)
WP-Cron is WordPress’s built-in task scheduler. Core uses it for things like update checks, and plugins use it for all kinds of automation: backups, cache warmers, email digests, subscription renewals, data syncs, and more. The key detail: WP-Cron checks scheduled tasks on page load. When a request comes in, WordPress looks at what’s due and tries to run it during (or just after) that request. (WordPress Developer Resources)
That approach leads to a few common failure modes:
1) Low-traffic sites
No visitors = no page loads = WP-Cron doesn’t run. Scheduled posts and background tasks can sit there until the next request.
2) High-traffic sites
Lots of page loads can mean WP-Cron spawns frequently, causing excess PHP work, overlapping runs, and resource spikes. This can be especially painful when multiple plugins schedule heavy tasks.
3) Loopback/HTTP requests blocked
WP-Cron often relies on spawning a request back to your site. If your host, firewall, plugin security rule, or server config blocks loopback requests (common with strict 403 rules), WP-Cron can fail and throw errors like “There was a problem spawning a call to the WP-Cron system…” (WordPress.org)
4) Caching can reduce cron triggers
Aggressive full-page caching can reduce PHP execution for many “visits,” which means fewer opportunities for WP-Cron to check and run tasks.
Real cron fixes these issues by running wp-cron.php on a predictable schedule directly at the server level—independent of website traffic.
Benefits when you replace WP-Cron with real cron
Replacing WP-Cron with system cron typically gives you:
- More reliable scheduled posts (no more “missed schedule” surprises)
- More reliable backups, imports, and WooCommerce tasks
- Fewer random CPU spikes from cron spawning on traffic
- Better performance consistency on busy sites because you control frequency
- Cleaner troubleshooting, because cron becomes deterministic
Hosting providers themselves often recommend this change on performance-sensitive setups. (DreamHost Knowledge Base)
Step 1: Confirm WP-Cron is actually the problem
Before changing anything, do a quick sanity check so you don’t fix the wrong thing.
Install a cron inspection tool (recommended)
Install WP Crontrol so you can view events, see what’s overdue, and run them manually. (WordPress.org)
What to look for:
- Events that are overdue by hours/days
- Repeating events that never seem to fire
- A huge number of scheduled tasks from a single plugin (could indicate a bug)
(Optional) Use WP-CLI to inspect cron
If you have SSH access, WP-CLI has a full cron command set (list schedules, run events, test spawning). (WordPress Developer Resources)
Examples you can run:
wp cron event listwp cron event run --due-nowwp cron test
If running due events manually works but they never run automatically, moving to real cron is a strong next step.
Step 2: Disable WP-Cron “on page load” (safe method)
You’re not disabling cron events entirely—you’re stopping WordPress from triggering cron on each page load. WordPress documents the exact constant to use:
Add this to wp-config.php (above the “stop editing” line):
define( 'DISABLE_WP_CRON', true );
This is the official method to disable WP-Cron’s page-load behavior. (WordPress Developer Resources)
Important: After you do this, you must set up a real cron job. Otherwise scheduled tasks will stop running.
Step 3: Add a real cron job (the right way)
The goal is to hit WordPress’s cron runner on a schedule. You generally have two reliable approaches:
Option A (Best): Run cron via WP-CLI
This avoids HTTP/WAF/cache complications because it runs locally on the server.
Typical cron entry (every 5 minutes):
*/5 * * * * cd /path/to/wordpress && /usr/bin/wp cron event run --due-now --quiet
Why it’s great:
- No loopback HTTP requests
- Less likely to be blocked by firewalls
- Typically faster and more reliable
Option B: Call wp-cron.php over HTTP(S)
This is common on shared hosting without WP-CLI.
Typical cron entry:
*/5 * * * * curl -s https://example.com/wp-cron.php?doing_wp_cron >/dev/null 2>&1
This method is widely used, but can be blocked by security rules or require allowlisting.
A common variation is wget instead of curl (same idea). (WordPress Development Stack Exchange)
How often should real cron run?
Most sites do well with every 5 minutes:
- Frequent enough for scheduled posts and most automation
- Not so frequent that it adds overhead
For busy WooCommerce sites or sites with lots of background jobs:
- Every 1 minute can be beneficial (especially for time-sensitive tasks)
- But only if your server can handle it
For very small sites:
- Every 10 minutes may be fine
If you’re unsure, start at 5 minutes, monitor, then adjust.
Setup instructions by hosting type
cPanel (shared hosting)
- Find Cron Jobs in cPanel.
- Choose a schedule (start with “Every 5 minutes”).
- Add a command.
HTTP method example:
curl -s https://example.com/wp-cron.php?doing_wp_cron >/dev/null 2>&1
WP-CLI method (only if WP-CLI is available):
cd /home/USER/public_html && wp cron event run --due-now --quiet
Tip: Some hosts require you to use a full PHP path or a specific shell—if your first run doesn’t work, check the cron job output email or logs.
Plesk
Use Tools & Settings → Scheduled Tasks and add either the WP-CLI or curl command.
Managed WordPress hosts
Many managed hosts provide their own cron tooling or recommend a specific approach. If you can’t access system cron, ask support if they can schedule a job for wp-cron.php or enable WP-CLI cron.
VPS / Dedicated (crontab)
SSH in and run:
crontab -e
Add your entry, save, then verify it’s installed:
crontab -l
Windows Server
Use Task Scheduler to run a scheduled task that calls:
- WP-CLI via
php wp-cli.phar(if configured), or - a PowerShell command to request
wp-cron.php
Testing checklist (do this right after setup)
1) Confirm scheduled events are running
- In WP Crontrol, note an event’s “Next Run”
- Wait 5–10 minutes
- Confirm it updates / runs as expected (WordPress.org)
2) Force-run due events
If you have WP-CLI:
wp cron event run --due-now
3) Confirm wp-cron.php is reachable (HTTP method only)
Open:
https://example.com/wp-cron.php?doing_wp_cron
You won’t see much, but it should not return a 403/500. If it does, see troubleshooting below.
Troubleshooting: why real cron still “doesn’t work”
Problem: 403 Forbidden when calling wp-cron.php
This often happens with:
- Security plugins blocking requests
- Cloudflare/WAF rules
- Server rules restricting access to
wp-cron.php - Hosts blocking loopback-style calls
The WordPress support forums commonly tie WP-Cron failures to blocked requests and unexpected response codes. (WordPress.org)
Fixes to try:
- Allowlist your server IP in firewall/WAF if needed
- Temporarily disable security plugin rules affecting
wp-cron.php - Use WP-CLI cron instead (bypasses HTTP entirely)
Problem: You disabled WP-Cron but forgot the real cron
Symptom: everything scheduled stops entirely.
Fix: Add the system cron job immediately (Step 3).
Problem: Caching / CDN interferes with HTTP cron
If using the HTTP method:
- Exclude
/wp-cron.phpfrom caching - Ensure your cron request is not being cached or blocked
Again, WP-CLI method avoids this entire class of issues.
Problem: Tasks run, but WooCommerce actions still back up
WooCommerce uses its own queue system (Action Scheduler). Even with real cron, a backlog can persist if:
- Server resources are constrained
- A plugin is generating huge queues
- Database autoload/options bloat is slowing admin/AJAX tasks
This is where performance tuning matters. If your site feels sluggish during background processing, consider a cleanup and speed pass:
- WP Fix It performance help: (WP Fix It)
- Database cleanup service (helps reduce bloat that can slow scheduled jobs): (WP Fix It)
Performance tips after you replace WP-Cron with real cron
Once you’ve stabilized scheduling, you can often squeeze even more performance and reliability by tackling the usual “cron amplifiers”:
1) Audit plugins that schedule too much
In WP Crontrol, look for plugins creating many events. If a plugin schedules dozens/hundreds of repeating tasks, it can cause constant load.
2) Keep PHP updated
Newer PHP versions typically improve performance and efficiency, which helps when cron jobs run regularly. WP Fix It has a practical guide to upgrading PHP safely. (WP Fix It)
3) Make sure updates and backups aren’t colliding
Don’t schedule heavy backups at the same minute as other heavy automation (imports, reports, cache preloads). Stagger them.
4) Reduce database overhead
Cron-heavy sites are often database-heavy. Cleaning transients, revising autoloaded options, and reducing bloat can dramatically improve cron throughput. (WP Fix It)
Recommended external references (deep dives)
If you want the official and hosting-provider perspectives:
- WordPress plugin handbook on cron basics (how WP-Cron works) (WordPress Developer Resources)
- WordPress
wp-config.phpdocumentation showingDISABLE_WP_CRON(WordPress Developer Resources) - WP-CLI cron commands (run due events, test spawning, list schedules) (WordPress Developer Resources)
- DreamHost guide to disabling WP-Cron and improving performance (DreamHost Knowledge Base)
- Bitnami documentation on moving cron to system scheduler (docs.bitnami.com)
These are informational references (not WordPress services), useful for verifying details and adapting steps to your environment.
Common “gotchas” you should avoid
- Don’t set cron to run too often without measuring. Every minute is fine for some sites, but it can be wasteful on small sites.
- Don’t rely on traffic-based cron for ecommerce. Orders, emails, renewals, and inventory syncs need reliability.
- Don’t ignore 403/loopback errors. If your server blocks cron calls, switch to WP-CLI cron.
- Don’t treat “missed schedule” as only a cron issue. Timezone misconfigurations, plugin conflicts, or database slowness can also contribute.
When to get help
If you’re running a business site, membership site, or WooCommerce store, cron reliability directly impacts revenue and customer experience. If you want this configured cleanly (and verified end-to-end), WP Fix It offers hands-on WordPress help and performance services:
- Services overview (WP Fix It)
- 24/7 WordPress support info (WP Fix It)
- Speed optimization service (WP Fix It)
And if a recent auto-update caused issues while you were troubleshooting cron, their rollback checklist can help you stabilize first, then optimize: (WP Fix It)
Quick summary
To Replace WP-Cron with Real Cron:
- Disable WP-Cron on page load by adding
define('DISABLE_WP_CRON', true);towp-config.php. (WordPress Developer Resources) - Create a system cron job to run every 5 minutes:
- Best: WP-CLI
wp cron event run --due-now --quiet(WordPress Developer Resources) - Alternative:
curl https://example.com/wp-cron.php?doing_wp_cron(WordPress Development Stack Exchange)
- Best: WP-CLI
- Test and monitor with WP Crontrol and/or WP-CLI. (WordPress.org)
Do that, and you’ll typically eliminate missed schedules while smoothing out performance spikes caused by cron running unpredictably.




