getNodi

Templates / WordPress cron

WordPress cron, driven from outside

WP-Cron is not cron. It runs when somebody loads a page, which means a quiet site runs its scheduled tasks late and a busy site runs them on a visitor’s request. This recipe replaces that with a fixed cadence.

The recipe

Request
GET https://{{domain}}/wp-cron.php?doing_wp_cron
Schedule
Every 5 minutes (*/5 * * * *)
Timeout
60s
Attempts
3
Counts as success
2xx

You supply

Your domain
example.com

Host only — no https:// and no trailing slash.

Why this job exists

WordPress ships its own scheduler, WP-Cron, and it is a reasonable design for a platform that cannot assume it has a crontab. On every front-end request WordPress checks whether anything is due and, if so, fires a loopback request to wp-cron.php to run it. No traffic, no check.

The consequence shows up in two opposite ways. On a low-traffic site — a blog, a staging environment, a brochure site with a hundred visits a day — scheduled posts publish hours late, backup plugins skip nights, and WooCommerce holds subscriptions in a pending state well past their renewal. On a high-traffic site the opposite bites: every page view pays the cost of the check, and one unlucky visitor’s request is the one that spawns the loopback.

Both are fixed the same way. Tell WordPress to stop scheduling itself, and have something outside the site call wp-cron.php on a cadence you choose.

Setting it up

Turn off the built-in trigger first. Without this line WordPress keeps firing its own loopback on page views and you have added a scheduler rather than replaced one — the tasks still run, just twice as often and at unpredictable moments. Add it to wp-config.php above the "That’s all, stop editing" comment:

wp-config.php

define( 'DISABLE_WP_CRON', true );

The URL below includes the ?doing_wp_cron query string. WordPress uses that parameter to recognise a legitimate scheduler invocation and skip the spawn check, so keep it. Five minutes is the cadence most sites want: fine enough that a post scheduled for 09:00 goes out at 09:05 rather than at lunchtime, coarse enough that PHP is not being woken constantly.

Checking it actually works

  • Install WP Crontrol, open Tools → Cron Events, and check that the "Next Run" column moves forward after a scheduled run rather than sitting in the past.
  • Schedule a test post for two minutes out and confirm it publishes within one cadence interval of its time.
  • In the run history here, a healthy wp-cron.php returns 200 with an empty body. A response containing HTML usually means a plugin intercepted the request.

Where it goes wrong

A security plugin blocks the request

Wordfence, iThemes Security and most WAF rules treat direct hits on wp-cron.php as suspicious and will start returning 403 after a few. Allowlist the caller by IP or by user agent. If the job goes red with 403 shortly after you enable it, this is why.

Basic auth or a staging password

Password-protected staging sites return 401 to everything, the scheduler included. Either exclude wp-cron.php from the protection or do not schedule staging at all.

A long-running task times out

wp-cron.php runs every due task in sequence, so one slow importer stalls everything behind it. The timeout here is 60 seconds; if you see it hit, the fix is on the WordPress side — find the task and move it to its own hook — not a longer timeout.

Questions

Do I still need DISABLE_WP_CRON if I call the endpoint externally?

Yes. Without it both triggers are live. Nothing breaks, but tasks fire on page views as well as on your schedule, which defeats the point of a predictable cadence and doubles the load you were trying to control.

How often should it run?

Five minutes suits nearly everyone. Go to one minute only if you publish to the minute or run WooCommerce subscriptions with tight renewal windows. Hourly is enough for a blog that posts a few times a week, and is what the free plan runs.

Is calling wp-cron.php safe to expose?

The endpoint is public on every WordPress install by default — you are not opening anything new. It runs only tasks WordPress has already scheduled, so the worst an attacker achieves by calling it is running your own tasks slightly early.

Will this fix scheduled posts stuck as "Missed schedule"?

Usually, yes — that error is almost always WP-Cron never having fired. If posts still miss after a few days of green runs, the cause is elsewhere, typically a plugin fatal error during the cron request.

Running it here

This is a preset in the product, not an illustration. Pick it in the dashboard, fill in the one value above, and the job is created, scheduled and enabled — with retries, a record of every run showing status, latency and response, and an alert the first time one fails. Secret values are encrypted at rest and never rendered back.

The free plan runs 3 jobs hourly and needs no card. Where a recipe wants a finer cadence than your plan allows, it is slowed to the fastest schedule you are permitted rather than rejected.