The double-send bug and the missed-day bug usually get treated as unrelated tickets, but they share the same root cause: WP-Cron depends on page load traffic that this site doesn’t reliably have. A real server cron trigger paired with a run-lock fixes both at once.
Code
Write a WP-Cron job that reliably runs on a low-traffic site
A daily-digest-email scenario explaining why pseudo-cron misses schedules on quiet sites, and how to pair a real server cron trigger with an overlap-safe lock.
Works with Claude / GPT900 uses★ 4.2
The prompt
code-reliable-wp-cron-job
I scheduled a daily digest email using `wp_schedule_event()` with the `daily` recurrence,
but it's missing days entirely, sometimes running two days late, and occasionally seems
to send the digest twice in the same day.
ENVIRONMENT: [this is a niche B2B site with maybe 20-30 visits per day, on standard
shared hosting, no server-level cron access is confirmed set up yet]
Fix this like a senior dev who understands WP-Cron's actual mechanics, in order:
1. Explain the core issue precisely: WP-Cron isn't a real cron daemon, it's a
pseudo-cron that only checks for due events when a page loads (`wp-cron.php` fires
via a request triggered by front-end traffic). On a site with 20-30 visits a day,
there can be multi-hour or even multi-day gaps with zero requests, so scheduled
events simply don't fire until the next visitor happens to load a page.
2. Recommend disabling the pseudo-cron trigger with `define('DISABLE_WP_CRON', true);`
in `wp-config.php`, and replacing it with a real system cron job (or the host's
control panel cron feature) hitting `wp-cron.php` via `wget` or `curl` on a fixed
schedule (e.g. every 15 minutes), which guarantees WP-Cron actually gets a chance to
run its due events regardless of visitor traffic.
3. Explain the double-send symptom: if two nearly-simultaneous requests both trigger
`wp-cron.php` (a visitor and the new server cron overlapping, or a monitoring
service also pinging the site), WordPress can start two overlapping cron runs before
the first one finishes and clears the scheduled event, causing the digest to fire
twice. Fix this with `wp_next_scheduled()` checked at the very top of the hook
callback plus a short-lived transient lock (e.g. `get_transient('digest_running')`)
released only after the mail send completes.
4. Verify no duplicate `wp_schedule_event()` registrations exist: check that the
scheduling code runs on `wp_schedule_event` behind an `if ( ! wp_next_scheduled(...) )`
guard on plugin activation, not on every page load, since re-scheduling the same
hook repeatedly is a separate common cause of the same doubled-send symptom.
5. Note the edge case: after switching to a real server cron, confirm the site's own
security setup (a firewall rule or security plugin) isn't blocking direct
`wp-cron.php` requests from the server's own IP, since some hardening configs
inadvertently block exactly the request this fix depends on.
Replace the schedule name, hook, and traffic pattern with your actual situation.