SnagbaneBlog Try Cron Verdict
Snagbane Blog / WP-Cron Is Not a Real Cron Job
WP-Cron explained

WP-Cron Is Not a Real Cron Job (And Why That Changes Everything)

"WP-Cron not running" and "cron job failed WordPress" are two of the most-searched WordPress problems there is, and a lot of the advice you'll find is chasing a bug that isn't really there. Here's the part almost nobody explains clearly: WP-Cron isn't a cron job at all. It's a WordPress feature that just happens to share the name, and understanding the difference explains most of the confusion.

What "cron" actually means (the real one)

A real cron job is a task your server's operating system runs on a fixed schedule, driven by the system clock — "every day at 2am, run this script," full stop, regardless of whether anyone visits the website. It doesn't need traffic. It doesn't need PHP to be loaded. It just runs, because the OS itself is watching the clock.

What WP-Cron actually is

WordPress doesn't have access to your server's real system cron by default (most shared hosting doesn't give ordinary users that kind of access), so it built its own workaround: every time a page on your site loads — a visitor, a bot, an API request, anything that triggers WordPress to boot up — WordPress checks a stored list of scheduled tasks and asks "is anything due right now?" If something is due, it runs it (or dispatches a background request to wp-cron.php to run it) as part of, or right after, that same page load.

That single design choice is the source of almost every "WP-Cron isn't running" report you'll ever see. WP-Cron doesn't run on a clock. It runs on traffic. No traffic, no check, no chance for anything scheduled to fire — even though nothing is actually broken.

Why this makes "is my cron broken" surprisingly hard to answer

Picture two completely different sites with the exact same symptom: a scheduled task hasn't run in six hours.

  • Site A is a busy store with thousands of visits an hour. Six hours of silence on a scheduled task is a real red flag — something is actually stopping WP-Cron from firing despite constant traffic.
  • Site B is a niche blog, or a staging site, or a B2B tool that only gets visits during business hours in one time zone. Six quiet hours overnight is completely normal. Nothing is broken; nobody happened to load a page.

A monitoring tool that only checks "how long since the last tick" and alarms past a fixed threshold will misjudge Site B constantly. That's the exact failure mode that's most common in "cron checker" plugins, and it's why so many site owners either ignore the alerts entirely (defeating the point of monitoring) or waste time investigating a problem that was never there.

SituationWhat it usually means
Heartbeat is stale, but the site has had no real visitors eitherNormal. Nothing has triggered WP-Cron to check in.
Heartbeat is stale despite genuine recent trafficA real problem — something is preventing WP-Cron from running or completing.
A specific task fired a bit later than scheduled, onceNormal. WP-Cron only checks on page load, so exact timing always drifts a little.
A specific task never fires at all, across many opportunitiesA real problem with that task's schedule or the plugin that registered it.

The fix for sites where this actually matters

If your site genuinely needs scheduled tasks to run on a predictable clock regardless of traffic — an online store processing abandoned-cart emails, a membership site billing renewals — the standard fix is to stop relying on visitor-triggered WP-Cron entirely. Add define('DISABLE_WP_CRON', true); to wp-config.php, then set up a real system cron job (through your host's control panel, or a server-level crontab) to hit wp-cron.php on a fixed schedule — typically every 5 to 15 minutes. That gives you the reliability of a real cron job without giving up WordPress's own task-scheduling API.

If your site doesn't have that kind of urgency, the default visitor-triggered behavior is genuinely fine — it just means the right question to ask isn't "how long has it been," it's "is this actually a quiet site, or is something actually stuck."

How to actually tell the difference, without guessing

This is the exact problem we built Cron Verdict to answer. It watches two separate signals instead of one: whether WP-Cron has run recently at all (the heartbeat), and whether each individually scheduled task fired within a reasonable grace window of when it was actually due. That combination is what lets it say "this is just a quiet site" instead of crying wolf on every low-traffic day — and still catch it immediately when a task genuinely goes silent on a site that's clearly getting visitors.

Stop guessing whether your cron is actually broken

Cron Verdict is free on WordPress.org — install it, and get an honest verdict instead of a raw timestamp to interpret yourself.

Get Cron Verdict →

Common questions about WP-Cron

Why does WP-Cron not run on time?

WP-Cron only checks for due tasks when something requests a page on your site — a visitor, a bot, or an API call. If nothing visits your site for a few hours, no scheduled task gets a chance to fire in that window, even though nothing is actually broken.

Should I disable WP-Cron and use a real server cron job instead?

On a low-traffic site, yes — setting DISABLE_WP_CRON to true and pointing a real system cron job at wp-cron.php on a fixed schedule (e.g. every 5 or 15 minutes) removes the dependency on visitor traffic entirely, and is the standard recommended fix for sites where tasks need to run reliably regardless of traffic.

How do I know if WP-Cron is actually broken, not just quiet?

Check two things: whether your site has had recent visitors at all, and whether the specific scheduled task in question has fired within a reasonable window of when it was due. A stale heartbeat despite real recent traffic is a real problem; a stale heartbeat on a site nobody has visited in hours usually is not.

Does a caching plugin stop WP-Cron from running?

Full-page caching can reduce how often WordPress itself actually loads on a visit, since a cached page can be served without ever executing PHP — which means fewer opportunities for WP-Cron's check to run. This is a common, often-overlooked cause of WP-Cron appearing to slow down after a caching plugin is installed.