What WP-Cron Actually Is (And Why It’s Not a Real Cron)
Every WordPress site ships with its own scheduling system called WP-Cron. WordPress uses it for anything that has to happen on a timer: publishing scheduled posts, checking for plugin and core updates, sending scheduled emails, running backups, clearing caches, syncing WooCommerce orders, and dozens of smaller jobs plugins register on their own.
Here is the catch that surprises most site owners: WP-Cron is not a real cron job. A real cron job runs on your server on a fixed schedule, triggered by the operating system whether anyone visits your site or not. WP-Cron, on the other hand, is a fake — a pseudo-scheduler. WordPress only checks whether anything is due when someone loads a page. No visit, no check. That one design detail explains most of the trouble people have with it.
How WP-Cron works in practice
The sequence looks like this. A visitor requests a page. WordPress wakes up, serves the page, and near the end of the request it spawns a separate background request to your own wp-cron.php file. That second request then runs any scheduled jobs that are due. Your visitor never sees it, but their page load was the trigger, and the spawned job can still eat server resources while they wait for the response.
On a busy site this design mostly works. There is almost always a visitor around to keep the queue ticking over. On a low-traffic site, a staging site, or a site that mostly gets visits in bursts, WP-Cron falls apart in two directions at once — jobs run late or not at all, and the occasional visitor gets randomly punished with a slow page.
Why WP-Cron Hurts Your Site (Especially on Low Traffic)
WP-Cron’s reputation as a performance problem is well earned, but it is worth being specific about how it hurts, because the fix differs per problem.
1. Random slow page loads for real visitors
Because WP-Cron runs on a visitor-triggered request, whoever happens to be the unlucky visitor when a heavy job is due gets to wait for it. A backup plugin that suddenly starts zipping your uploads folder, an importer syncing thousands of products, or a security scan — all of these can fire on the same background request triggered by someone’s click. The page they opened may finish loading slowly because server CPU was busy running the job. If you have ever seen unexplained slow loads a few times a day with no traffic spike, WP-Cron is a prime suspect. It is one of the causes behind a sluggish admin area too, covered in our guide on why the WordPress admin gets slow.
2. Missed schedules on low-traffic sites
The flip side: if nobody visits your site at 3 a.m., the scheduled backup at 3 a.m. does not run at 3 a.m. It runs when the first visitor arrives in the morning. Scheduled posts go live late. Update checks bunch up. Anything time-sensitive — like sending a price-drop email to a customer list or expiring a promotion — can miss its window entirely. If your site gets fewer than a few hundred visits a day, this is not a theoretical problem; it is a daily one.
3. The traffic-based race
WP-Cron also misbehaves on sites that get bursty traffic. When traffic spikes, many page loads can each try to spawn wp-cron.php at once. WordPress has locking to prevent true duplicates, but high-frequency triggers still add up to extra requests hammering your own server — wasted CPU and occasionally a surge of database writes right when the server is already busy. The effect shows up in Time to First Byte, the metric our TTFB troubleshooting guide walks through.
4. wp-cron.php as a target
The file is publicly reachable by design, so bots and scanners ping it constantly. Each of those pings can wake WordPress fully and trigger a schedule check. On shared hosting, dozens of bot-triggered cron checks a day are wasted load you never see in analytics. Rate-limiting or blocking direct requests to wp-cron.php is good hygiene either way, but it is not a substitute for replacing the trigger mechanism.
When You Should (and Shouldn’t) Replace WP-Cron
Disabling WP-Cron is not an automatic win for everyone. Be honest about your situation:
- Replace it if your site gets low to moderate traffic, has scheduled posts or time-sensitive jobs, runs backups or security scans on a schedule, or shows unexplained slow loads a few times a day.
- Replace it if you run WooCommerce — order emails, inventory syncs, and scheduled events are exactly the jobs that go wrong when they run late.
- You can skip it on a genuinely high-traffic site where nothing ever goes missing and your host already manages cron-like scheduling (some managed hosts disable WP-Cron and handle it for you — check before duplicating their work).
- You can skip it on a brochure site with no scheduled posts, no backups, no newsletters — there is barely anything for the queue to do.
A useful rule: if any plugin you depend on registers scheduled tasks (check with the WP Crontrol plugin — more on that below) and your site is not busy around the clock, a real cron job is worth the ten minutes it takes to set up.
Step 1: See What’s Actually Scheduled (WP Crontrol)
Before changing anything, look at what is queued. Install the free WP Crontrol plugin (Tools → Cron Events after activation). You will see every scheduled event, its hook name, its recurrence, and when it next runs. Pay attention to three things:
- Events with no recurrence (one-off jobs): these are usually fine — they run once and disappear.
- Very frequent events (every minute, every 5 minutes): often from analytics or sync plugins. These are the ones making the most wp-cron requests.
- Failed or overdue events: anything flagged as overdue is direct evidence WP-Cron is already failing on your site.
Write down the frequent hooks. If one of them is firing every few minutes and your page loads occasionally feel sluggish, you have found your culprit.
Step 2: Disable WP-Cron the Safe Way
Disabling WP-Cron is a one-line change in your wp-config.php file. Add it just above the line that says /* That's all, stop editing! Happy publishing. */:
define( 'DISABLE_WP_CRON', true );
That single line stops WordPress from triggering wp-cron.php on page loads. Critical: this does not run your jobs — it stops them. If you add this line without setting up a real cron job in Step 3, scheduled posts will never publish, update checks will never run, and backups will never start. Do both steps in the same sitting.
How to edit wp-config.php:
- cPanel / Hostinger hPanel: File Manager → public_html → wp-config.php → Edit.
- FTP/SFTP: download wp-config.php, edit it locally, upload it back.
- Always take a backup before editing. If you paste the line in the wrong place and get a white screen, remove it via FTP and the site comes back.
Step 3: Set Up the Real Server Cron Job
A server cron job is the operating-system scheduler. It runs on time, every time, with zero dependence on visitors. Every host supports them; the exact screens differ.
cPanel (most shared hosts)
- Open Cron Jobs in cPanel.
- Add a new cron job. Set the interval — every 15 minutes is the sweet spot for most sites (every 5 minutes if you have very frequent plugin tasks; hourly if the site is mostly static).
- Command — use one of these two forms:
wget -q -O - "https://yourdomain.com/wp-cron.php?doing_wp_cron" >/dev/null 2>&1
or, if your host prefers PHP directly:
php /home/yourusername/public_html/wp-cron.php >/dev/null 2>&1
Replace
https://yourdomain.comwith your real domain and the/home/yourusername/public_htmlpath with your actual account path (cPanel’s File Manager shows it at the top). - Save. The server will now call wp-cron.php on schedule.
Hostinger hPanel
- Go to Advanced → Cron Jobs.
- Create a new job, choose your interval (every 15 minutes works well).
- Use the wget-style command above with your real domain, and make sure the
?doing_wp_cronparameter is present — it tells WordPress this is a cron call, not a visitor request.
What the command is doing
You are not deleting wp-cron.php. You are changing who calls it: instead of an unlucky visitor’s page load triggering it at a random moment, your server calls it on a fixed, quiet schedule. Jobs still run exactly the way WordPress expects — they just run on time and off your visitors’ backs.
Picking the right interval
- Every 15 minutes: the default recommendation. Fine for scheduled posts, updates, backups, and most plugin jobs.
- Every 5 minutes: only if WP Crontrol showed jobs that genuinely need to run that often (some forms, analytics, or membership plugins do).
- Hourly: acceptable for a brochure site where nothing time-sensitive is scheduled.
Do not set it to every minute “just to be safe.” Each run wakes WordPress and checks the queue; minute-level runs on shared hosting are pure overhead for zero practical gain.
Step 4: Verify Everything Actually Works
This is the step most tutorials skip, and it is the one that matters most. Verification takes five minutes:
- Confirm the trigger is server-side: watch your access logs for one interval and confirm wp-cron.php is being hit on schedule (and by your server/Wget user agent, not random IPs).
- Confirm jobs run on time: schedule a test post for a few minutes in the future and watch it publish at the exact time. Before this fix, it would have gone live whenever the next visitor showed up.
- Re-check WP Crontrol: the overdue/missed events you saw before should stop accumulating.
- Watch page speed for a day: those random slow loads should disappear. Run your homepage through PageSpeed a few times and compare — and if the numbers are still off, our 20-step performance checklist covers everything else that affects them.
- Block direct external pings to wp-cron.php (optional but recommended): add this to .htaccess:
<Files "wp-cron.php"> Require all denied </Files>This stops bots from waking WordPress through the cron endpoint. Your server-side cron command still works because it runs locally, not over the public web (the wget form uses HTTP but includes the cron parameter — if your host blocks external loopback, use the PHP form instead).
Common Mistakes That Break Things
- Disabling WP-Cron without adding the server cron: the classic error. Scheduled posts stop, update notifications go silent, backups never run. If you already did this, add the server cron job now — everything resumes on the next scheduled tick.
- Wrong path in the cron command: the PHP form needs your exact account path. Use cPanel’s File Manager to confirm it; a guessed path fails silently.
- Running too often: every-minute cron jobs on shared hosting can get you flagged for resource abuse. Fifteen minutes is enough.
- Forgetting the change during migration: the DISABLE_WP_CRON line lives in wp-config.php, so it travels with your file copy — but the server cron job lives in your old host’s control panel and does not migrate. After any host move, recreate the cron job immediately or schedules go dark.
- Assuming the host handles it: some managed WordPress hosts replace WP-Cron automatically, but most shared hosts do not. Check your host’s documentation before assuming.
The Bottom Line
WP-Cron is a clever workaround for a web without schedulers, and on a busy site it quietly does its job. But for most real-world sites — low-traffic sites, WooCommerce stores, anything with scheduled content — it is a source of random slowdowns and missed deadlines. Swapping it for a real server cron job takes one line of config and one scheduled task, and it is one of the few optimizations that improves both speed and reliability at the same time. Once it is running, verify with WP Crontrol and a test post, then move on to the next item on your optimization list — like getting your caching layer right with a CDN, for example our guide on setting up Cloudflare APO.


2 Comments on “WP-Cron Explained: Disable It and Set Up a Real Cron Job”