DEV Community

ShoHost
ShoHost

Posted on

WP-Cron Is Not a Cron: Moving WordPress to a Real Scheduler on cPanel

WordPress has a scheduler called WP-Cron, and it handles more than most people realise: scheduled posts, WooCommerce order cleanups, backup plugins, security scans, update checks. The catch is in how it runs. WP-Cron isn't a real cron job. It only fires when someone visits your site.

That one design choice causes two opposite problems:

  • Quiet sites miss jobs. If nobody visits at 3 AM, the 3 AM backup doesn't start until the first visitor arrives. Scheduled posts show "Missed schedule".
  • Busy sites run it too often. On every page load, WordPress checks whether anything is due and may spawn a loopback request to wp-cron.php. Under traffic, that adds up to a lot of pointless PHP work.

The fix is the same on almost any cPanel account: switch off the visit-triggered version and call WP-Cron from the server's own scheduler instead.

1. Turn off the page-load trigger

Open wp-config.php and add this line above /* That's all, stop editing! */:

define( 'DISABLE_WP_CRON', true );
Enter fullscreen mode Exit fullscreen mode

This doesn't remove WP-Cron. Scheduled events still exist; they just stop firing on page loads. Don't save this change without doing step 2, or nothing scheduled will run at all.

2. Add a real cron job in cPanel

In cPanel, open Advanced > Cron Jobs, pick a schedule, and add a command. Every 5 minutes is a sensible default for most sites; every 15 is fine for a small blog.

The most reliable command runs WordPress through PHP directly, so it doesn't depend on DNS, SSL or a firewall letting a request back in:

cd /home/USERNAME/public_html && /usr/local/bin/php wp-cron.php > /dev/null 2>&1
Enter fullscreen mode Exit fullscreen mode

Replace USERNAME and the path with your own. If WP-CLI is available on your account, this is even cleaner, because it only runs events that are actually due:

cd /home/USERNAME/public_html && wp cron event run --due-now > /dev/null 2>&1
Enter fullscreen mode Exit fullscreen mode

Check which PHP binary matches your site's PHP version. On many cPanel servers the default php in cron is a different version from the one your site uses, which is a classic "works in the browser, fails in cron" cause. Your host's docs or which php over SSH will tell you the right path.

3. Check it's actually running

Install a cron viewer plugin such as WP Crontrol for a few days, or run:

wp cron event list
Enter fullscreen mode Exit fullscreen mode

Look at the "next run" column. If events keep sliding into the past and never run, the cron command is failing. Remove > /dev/null 2>&1 temporarily and set a cron email address in cPanel so you can see the error.

4. A few things to watch

  • Multisite: each site has its own queue. With WP-CLI, loop over wp site list --field=url and pass --url= to each run.
  • Heavy jobs: if a backup plugin runs for 20 minutes, a 5-minute cron can start overlapping runs. Most backup plugins lock themselves, but check.
  • Staging copies: clone a site and you clone DISABLE_WP_CRON. Add the cron job on staging too, or turn the constant off there.

This takes ten minutes and makes scheduled tasks predictable, which is usually what people actually wanted when they scheduled them. If you'd rather start on hosting that already gives you cPanel cron, SSH and a choice of PHP versions out of the box, take a look at ShoHost's cPanel WordPress hosting.

Top comments (0)