Run WordPress cron from the system scheduler
Disable page-load WP-Cron and run due events from a real server cron job with WP-CLI, including multisite and troubleshooting.
On this page
By default, WordPress checks for scheduled tasks (WP-Cron) on every page load. On busy sites that adds overhead to visitor requests, and on quiet sites scheduled posts, WooCommerce emails, and Action Scheduler jobs run late or not at all. Moving WP-Cron to the server's scheduler fixes both problems. Do this on every site Avunu hosts.
1. Disable Page-Load Cron
Add this to wp-config.php above the /* That's all, stop editing! */ line:
define( 'DISABLE_WP_CRON', true );Or from the WordPress directory:
wp config set DISABLE_WP_CRON true --rawThis only stops page loads from spawning cron. Events are still scheduled as usual and run when something triggers them, which the next step handles.
2. Add a System Cron Job
Edit the crontab of the user that owns the WordPress files (not root), for example sudo crontab -u www-data -e, and add:
*/5 * * * * wp cron event run --due-now --path=/var/www/example.com/htdocs --quiet--due-nowruns only events whose time has come.--pathpoints at the WordPress root, so the job doesn't depend on the working directory.--quietkeeps cron from emailing output on every run. Errors still go to stderr.Cron's
PATHis minimal. Ifwpisn't in/usr/binor/usr/local/bin, use its full path (command -v wpshows it).
Every five minutes suits most sites. Use * * * * * for stores that depend on timely Action Scheduler jobs (subscription renewals, webhooks).
Tip
Many hosting control panels have a "Cron Jobs" screen for this. Enter the same command there, running as the web app's system user.
Without WP-CLI
If WP-CLI isn't available, request wp-cron.php over HTTP instead:
*/5 * * * * curl -fsS -o /dev/null "https://example.com/wp-cron.php?doing_wp_cron"This goes through the web server, so it's subject to PHP-FPM timeouts and any firewall or basic-auth rules on the site. WP-CLI runs in PHP's command-line mode with no web timeout, so prefer it.
Multisite
wp cron event run only handles one site at a time. Loop over every site in the network:
*/5 * * * * cd /var/www/example.com/htdocs && wp site list --field=url | xargs -I{} wp cron event run --due-now --url={} --quiet3. Verify
From the WordPress directory:
wp cron event list --fields=hook,next_run_relative,recurrence
wp cron event run --due-nowwp cron event list should show nothing with a past next_run_relative a few minutes after the cron job is in place. Site Health (Tools > Site Health) also flags late scheduled events.
Troubleshooting
| Symptom | Check |
|---|---|
| Events pile up as overdue | The crontab line is under the right user, wp is in cron's PATH, and --path is correct. Run the command by hand as that user. |
| Duplicate runs or race conditions | Page-load cron is still on. Confirm with wp config get DISABLE_WP_CRON. |
| WooCommerce "Pending" scheduled actions keep growing | Action Scheduler runs from WP-Cron. Check WooCommerce > Status > Scheduled Actions, or work through the queue with wp action-scheduler run. |
| Object cache plugin's own cron service is enabled | Turn off external cron-pinging services (for example Docket Cache's Cronbot) once the server cron works. |
Sources
This article is in the public domain (CC0 1.0), code samples included. Use it however helps you.