WP-Cron is the system WordPress uses to run scheduled jobs like publishing posts, sending emails, and clearing caches. The catch: it is not a real cron job. WP-Cron only runs when someone visits your site, so on a quiet site it fires late and on a busy site it fires far too often. That single fact explains most “my scheduled post did not publish” problems.
Why WP-Cron is not real cron
A real system cron runs on a fixed clock, every minute or every hour, whether or not anyone is around. WP-Cron is different. On each page load, WordPress checks whether any scheduled task is due and, if so, runs it in the background. No visitors means no checks, which means nothing runs.
This causes two opposite problems:
- Low-traffic sites run it late. A post scheduled for 9:00 AM will not publish until the next visitor shows up, which might be hours later.
- High-traffic sites run it too often. Every visit triggers the check, so a busy site spawns the loopback request over and over, draining CPU and PHP workers for no benefit.
If you want a plain-English breakdown of what is scheduled on your site and how often it should run, the WordPress Cron Explainer lays out each event and its interval.
Common WordPress cron intervals
WordPress ships with three default recurring schedules. Tasks register against one of these:
- hourly - runs every 60 minutes (cache cleanup, some plugin syncs).
- twicedaily - runs every 12 hours.
- daily - runs every 24 hours (update checks, log pruning).
Plugins can register custom intervals too, but these three cover most of what runs on a standard install. Knowing the interval tells you how stale a missed task can get before it self-corrects.
The reliable fix: disable WP-Cron and use a real cron
The fix is to stop WordPress from triggering cron on page loads and hand the job to your server instead. Two steps:
- Open
wp-config.phpand add this line above the “stop editing” comment:define('DISABLE_WP_CRON', true);. This turns off the traffic-triggered behavior so visits no longer fire the loopback request. - Set up a real server cron to run WordPress cron on a fixed schedule, every 5 to 15 minutes.
For step 2, the cleanest option is WP-CLI: wp cron event run --due-now. A crontab entry every five minutes looks like this:
*/5 * * * * cd /path/to/wordpress && wp cron event run --due-now
If WP-CLI is not available, call the file directly with a tool like wget or curl:
*/5 * * * * wget -q -O - https://yoursite.com/wp-cron.php?doing_wp_cron
Either way, your scheduled tasks now run on a predictable clock with zero dependence on traffic. To confirm what should be firing and when after you switch, run your event list back through the WordPress Cron Explainer and compare it to your cron timing.
Related tools
- Cron Expression Explainer - decode the
*/5 * * * *syntax in your crontab line. - PHP-FPM Calculator - size your worker pool so cron and visitors do not starve each other.
- WordPress Memory Estimator - check that cron tasks have enough memory headroom to finish.
Disable WP-Cron, hand it to a real cron, and your schedule finally runs on time.