Skip to content
Skip to the article
In WordPress: 10 articles
WordPress

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.

Updated
Applies to
  • WordPress 6.x
  • WP-CLI 2.x
Tags
  • wordpress
  • cron
  • wp-cli
  • performance
Reading time
3 min

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 --raw

This 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-now runs only events whose time has come.

  • --path points at the WordPress root, so the job doesn't depend on the working directory.

  • --quiet keeps cron from emailing output on every run. Errors still go to stderr.

  • Cron's PATH is minimal. If wp isn't in /usr/bin or /usr/local/bin, use its full path (command -v wp shows 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={} --quiet

3. Verify

From the WordPress directory:

wp cron event list --fields=hook,next_run_relative,recurrence
wp cron event run --due-now

wp 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

SymptomCheck
Events pile up as overdueThe 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 conditionsPage-load cron is still on. Confirm with wp config get DISABLE_WP_CRON.
WooCommerce "Pending" scheduled actions keep growingAction 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 enabledTurn 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.