21 Apr 2018 20:42 • Last updated: 14 Nov 2025 16:57 by Ivan • Performance, WordPress # # # #

Disable default WP cron job for performance (and do it the right way)

TL;DR: WordPress’ built‑in cron (WP‑Cron) runs on page loads. On busy sites it can add overhead; on quiet sites it can miss schedules. The fix is simple: disable the default trigger in wp-config.php and run wp-cron.php from a real scheduler (Linux cron, Windows Task Scheduler, or a third‑party ping) every 5–10 minutes. Verify with WP‑CLI and keep an eye on heavy jobs like WooCommerce’s Action Scheduler.

Why WP‑Cron hurts performance

WP‑Cron is a pseudo cron. It checks for due tasks on each page request and then tries to run them. That creates two common problems:

  • High traffic: each request can spawn cron work, competing with real visitors for PHP workers and CPU. You’ll see extra concurrent requests to /wp-cron.php during spikes.
  • Low traffic: jobs only run when someone visits, so “publish at 08:00” becomes “publish whenever the next person arrives.”

Typical symptoms: random slow spikes, scheduled posts missing their time, WooCommerce emails delayed, backups overlapping with peak traffic, or admin notices like “there was a problem spawning a scheduled task.”

When you should disable the default WP‑Cron trigger

You almost always benefit on production, especially if:

  • You run WooCommerce or anything using Action Scheduler (marketing automations, imports/exports, webhooks). See WooCommerce’s Scheduled Actions docs.
  • You have backups, feeds, or syncs scheduled.
  • You use full‑page caching/CDN and want deterministic timings.
  • You’ve seen missed schedule or spawn errors in the logs.

Local dev and tiny brochure sites can leave it as‑is, but standardising on a real cron keeps behaviour consistent across environments.

What “real cron” is (and how it differs from WP‑Cron)

A real cron is the operating system’s time‑based scheduler. On Linux and other UNIX‑like systems it’s provided by the cron daemon (crond). Jobs live in a crontab and run at the exact times you define – independent of web traffic, browsers, or PHP workers.

A minimal crontab entry looks like this:

# ┌ minute (0–59)
# │ ┌ hour (0–23)
# │ │ ┌ day of month (1–31)
# │ │ │ ┌ month (1–12)
# │ │ │ │ ┌ day of week (0–7, Sun=0 or 7)
# │ │ │ │ │
# * * * * *  command to run

Windows offers a similar system via Task Scheduler, where you define a trigger (e.g., every 5 minutes) and an action (e.g., call wp-cron.php or run wp.exe cron event run --due-now).

Real cron vs WP‑Cron at a glance

  • Trigger source: Real cron is driven by the OS clock; WP‑Cron is triggered on page load (an HTTP request).
  • Timing accuracy: Real cron runs to the minute you set; WP‑Cron runs “whenever someone visits.” Quiet sites miss exact times; busy sites may spawn competing runs.
  • Execution environment: Real cron usually runs CLI commands (PHP CLI, shell scripts, binaries) outside the web server and CDN. WP‑Cron executes inside a web request to /wp-cron.php, inheriting web timeouts, WAF/CDN rules, and PHP‑FPM worker limits.
  • Resource isolation: Real cron jobs are separate processes and can be constrained/tuned (e.g., nice, ionice, systemd units, concurrency). WP‑Cron competes with front‑end PHP workers, causing spikes during traffic peaks.
  • Reliability/observability: Real cron integrates with system logging and exit codes; failures are easier to track and alert on. WP‑Cron failures can be silent until the next visitor or show “spawn” warnings in admin.
  • Security and access: Real cron requires server access (or a trusted external pinger). WP‑Cron can be blocked by auth, firewalls, or cache layers.
  • Multisite behaviour: One scheduler can cover a whole network with wp cron event run --due-now from the network root. With WP‑Cron, timing depends on visits across subsites.

Bottom line: WP‑Cron is a convenient fallback but not a scheduler. Production sites should disable its page‑load trigger and use a real scheduler to fire jobs predictably.

Step 1 – Disable WP‑Cron on page load

Edit wp-config.php and add this above the line that says “That’s all, stop editing! Happy publishing.”

// Disable the default WP‑Cron trigger (runs on page load)
define('DISABLE_WP_CRON', true);

This does not disable WordPress’ scheduling system itself; it only stops the automatic trigger on page views. You’ll provide your own trigger in the next step.

Pro tip: If you previously enabled the fallback ALTERNATE_WP_CRON, remove it now to avoid odd redirects and ?doing_wp_cron URLs.

Step 2 – Replace it with a real scheduler

Pick one of these options. The goal is simply to hit wp-cron.php on an interval.

A) Linux server (crontab)

Run every 5 minutes (safe default for most shops and blogs):

*/5 * * * * wget -q -O - https://example.com/wp-cron.php?doing_wp_cron >/dev/null 2>&1

Prefer curl?

*/5 * * * * curl -s https://example.com/wp-cron.php?doing_wp_cron >/dev/null 2>&1

Further reading: Kinsta’s walkthrough on disabling WP‑Cron and scheduling a system cron.

If you host multiple sites on one box, stagger them (e.g., */5 plus different minute offsets) to avoid bursting all jobs at once.

B) WP‑CLI (no HTTP request)

If you have SSH access, you can execute due events via WP‑CLI:

*/5 * * * * /usr/bin/wp --path=/var/www/example.com/public_html cron event run --due-now >/dev/null 2>&1

This runs jobs directly in PHP/CLI, bypassing web server constraints and some cache/CDN quirks. See WP‑CLI: wp cron event list, wp cron event run, and wp cron test.

C) Windows Task Scheduler

Create a Basic Task that runs every 5–10 minutes and executes:

powershell "Invoke-WebRequest https://example.com/wp-cron.php"

Reference: WordPress Plugin Handbook: Hooking WP‑Cron into the system task scheduler.

D) Third‑party ping service

If your host doesn’t expose cron, use a reliable external pinger (EasyCron, cron-job.org, etc.) to GET https://example.com/wp-cron.php?doing_wp_cron on your desired schedule.

Verifying it works (and monitoring)

Use WP‑CLI for instant feedback:

# List scheduled events
wp cron event list

# Manually run anything that is due now
wp cron event run --due-now

# Test the spawn system (helpful before you switch)
wp cron test

Docs: WP‑CLI – event list, event run, cron test.

What to look for:

  • No growing backlog of overdue jobs.
  • Heavy hooks (backups, imports, wc_*) finish within your interval.
  • Scheduled posts/emails go out on time.

Gotchas and production notes

  • Caching/CDN: Some page caches or security layers can block wp-cron.php. Whitelist it and bypass full‑page cache for that path. If your CDN uses “Under Attack” modes, scheduled jobs may stall.
  • Basic/Auth or maintenance mode: If the site requires auth, wp-cron.php will need credentials or a CLI approach.
  • ?doing_wp_cron parameter: Totally fine to keep; it ensures the cron request isn’t cached and helps WordPress track a run. More info: Why is ?doing_wp_cron being appended to my URLs?.
  • Multisite: One network‑level trigger is typically enough; subsites’ jobs will run when WordPress loads. If you rely on domain‑mapped subsites with separate traffic patterns, consider WP‑CLI’s --due-now from the network root.
  • Intervals: 5 minutes is a practical starting point. Low‑activity sites can push to 10–15 minutes; busy shops sometimes go to 1–2 minutes for time‑sensitive flows.
  • Stagger the heavy stuff: If imports, backups, and marketing automations all line up at 00/05/10, move some to 02/07/12 to avoid spikes.
  • Plugins that assume page‑load cron: Rare today, but if a plugin expects the page‑load trigger, keep an eye on it after switching.

Rollback

Need to revert quickly? Remove the DISABLE_WP_CRON line and delete your server task. WordPress will go back to page‑load triggering immediately.

FAQ

Will disabling WP‑Cron break scheduled posts?
No – provided you replace the trigger with a real scheduler. Scheduled posts (and everything else) keep working; they just run on your exact interval.

What frequency should I choose?
Start with every 5 minutes. If jobs routinely finish in seconds and you don’t need minute‑level precision, try 10–15 minutes. If you run a busy WooCommerce store with time‑sensitive automations, 1–2 minutes can be justified.

How do I see what’s actually scheduled?
wp cron event list is the fastest way. For a GUI, the WP Crontrol plugin is solid on staging. On production, prefer WP‑CLI and logs.

Why do I still see ?doing_wp_cron in URLs?
You likely had ALTERNATE_WP_CRON enabled at some point; remove it. Some tools append it intentionally on cron pings – it’s harmless.

Next steps / Need a hand?

We’ve implemented this on high‑traffic blogs, WooCommerce shops, and content platforms. If you’d like us to audit and harden your WordPress performance – from cron to caching, PHP workers, and database autoloads – get in touch.
We’ve implemented this on high‑traffic blogs, WooCommerce shops, and content platforms. If you’d like us to audit and harden your WordPress performance – from cron to caching, PHP workers, and database autoloads – get in touch.

Related reading

Leave a Reply

Your email address will not be published. Required fields are marked *

Disable default WP cron job for performance (and do it the right way)

by Ivan time to read: 6 min
0