# A Preload That Never Ends and a Preload That Never Started Look the Same

> A preloader that never finishes is either walking a lap longer than the cache lifetime, or it never queued a list at all. Two commands tell the two apart.

- Published: 2026-09-24
- Updated: 2026-10-04
- Author: xSpeed Cache Team
- Tags: Caching, Troubleshooting, Performance, WordPress, fix:cache-preload, platform:wordpress
- Canonical: https://xspeedcache.com/blog/cache-preloader-never-finishes/

---

Updated September 2026

A default WordPress sitemap carries up to 2,000 URLs per page, per the [`wp_sitemaps_max_urls` reference](https://developer.wordpress.org/reference/hooks/wp_sitemaps_max_urls/) on developer.wordpress.org, checked 24 September 2026. WP-Optimize ships a 10-hour cache lifespan by default, per its own readme on the same day. Set those two numbers side by side and the question changes. It is not "why is my preloader stuck". It is whether the warmer can finish a lap before the first page it warmed goes cold. Different faults, different fixes, and the panel shows the same spinner for both.

This guide covers cache warming on WordPress: telling an empty queue from a slow one, and what to change in each case.

## Quick Summary: Which of These Three Is Happening

| If the symptom looks like… | Do this | Why |
|:---|:---|:---|
| Counter sits at 0, panel says ready | Check whether the sitemap is readable | A warmer with no list queues nothing and reports success |
| A handful warm, then hours of nothing | Check the scheduler is ticking | WP-Cron fires on page loads, not a clock |
| It runs constantly, never reports done | Run the walk test below | The lap outruns the cache lifetime |

## Confirm the Symptom Before You Change a Setting

Two commands separate an empty queue from a slow one. Run both over WP-CLI.

```bash
wp cron event list --fields=hook,next_run_relative | grep -i preload
wp xspeed preloader status
```

The first shows whether the scheduler holds the job and when it next expects to run. A `next_run_relative` already in the past means the event is due and nothing is collecting it.

**A queue of zero under a healthy-looking panel is the most misread state here**, and it is a fault we shipped ourselves: until xSpeed Cache 1.1.5 on 11 August 2026, our preloader reported "Ready" over a run that had queued nothing. For the outside view, run the [free xSpeed Scan](https://xspeedcache.com/scan/) against a page that should already be warm. To check by hand, our guide on [how to check whether WordPress caching is actually working](https://xspeedcache.com/blog/check-wordpress-caching-working/) walks the header method.

## The Walk Test: Can This Preload Finish a Lap At All

**Time to walk the list = pages ÷ pages warmed per hour.** If that time is longer than your cache lifetime, the first page you warmed is stale before you reach the last one. The warmer is not stuck. It is losing a race, and every lap restarts it.

![Two preload laps on one time axis. At 600 pages an hour a 2,000-page lap takes 3h 20m and fits inside a 10-hour cache lifetime. At 120 an hour it takes 16h 40m and does not.](https://xspeedcache.com/images/blog/cache-preloader-never-finishes-walk-test.webp)

| Pages in the list | Warmed per hour | Time for one lap | Cache lifetime | Finishes? |
|---:|---:|---:|---:|:---:|
| 2,000 | 600 | 3h 20m | 10 hours | ✅ |
| 2,000 | 120 | 16h 40m | 10 hours | ❌ |
| 12,000 | 600 | 20 hours | 10 hours | ❌ |

The rows are arithmetic, not measurements. Vendors document both sides without naming the trap, and all three sources below were read on 24 September 2026.

| What the source says | Where it comes from |
|:---|:---|
| A lower cache lifespan means "more preload processes", and high load means raising the interval | [WP-Optimize](https://wordpress.org/plugins/wp-optimize/) readme, v4.7.0 |
| Preloading "will visit each page of your site", and "can take some time" on a large one | WP Super Cache readme, v3.1.3 |
| Warns when the lifetime is shorter than the interval, "which would leave pages permanently uncached" | our own 1.1.1 changelog, 28 July 2026 |

The last row is the walk test enforced in code. xSpeed Cache, our WordPress caching plugin at WPDeveloper, has shipped that warning since July.

## The Queue Is Empty and the Panel Looks Fine

![The five stages of a preload: sitemap read, URLs queued, scheduler tick, HTTP fetch, cache written. Three of them fail quietly, and each written page starts its own expiry countdown.](https://xspeedcache.com/images/blog/cache-preloader-never-finishes-break-points.webp)

A warmer needs a list. Three documented ways the list comes back empty:

- 🗺️ **The sitemap is unreadable.** Two setups that are not misconfigurations do it: a site discouraging search engines, where WordPress disables the sitemap outright, standard on staging; and an SEO plugin serving its sitemap at a path the cache plugin never learned. xSpeed Cache 1.1.5 fell back to warming recent content for both.
- 🔒 **The warmer is off and cannot be switched on from WordPress.** [LiteSpeed Cache](https://wordpress.org/plugins/litespeed-cache/), at 7 million installs, answers this in its own FAQ: "The crawler is disabled by default, and must be enabled by the server admin first." On shared hosting that is not a setting you own.
- 🛡️ **The firewall is eating the requests.** A warmer fetches your own pages over HTTP, and rule sets judge it by its user agent. We shipped a fix on 22 September 2026 in xSpeed Cache 1.3.5 for warming requests that identified themselves in a way common 7G and 8G rule sets block, which silently stopped new posts being warmed.

## The Queue Never Drains, Because the Clock Is Not Ticking

This one is structural, and it catches quiet sites hardest. WordPress schedules background work with WP-Cron, and [the plugin handbook](https://developer.wordpress.org/plugins/cron/) is unambiguous about what that means: "WP-Cron does not run constantly as the system cron does; it is only triggered on page load. Scheduling errors could occur if you schedule a task for 2:00PM and no page loads occur until 5:00PM."

So on a quiet site the warmer's rate is not pages per hour. It is pages per visitor, and the sites that most need a warm cache are the ones where the fewest visitors arrive to warm it. Move the job to a real system cron and set `DISABLE_WP_CRON` to true in `wp-config.php`, which is the handbook's own procedure.

## Warming a Fleet Without Watching Each Dashboard

At twenty-five client sites the walk test stops being arithmetic you do once. Sitemaps grow, hosts throttle differently, and the site that stopped warming is the one the client tells you about. [xSpeed Hub](https://xspeedcache.com/xspeed-hub/) reads preloader state across every connected site at once, and `wp xspeed preloader status` answers a script or an AI assistant over MCP.

Run the free scan on your own site: [xspeedcache.com/scan/](https://xspeedcache.com/scan/)

When the host caps the rate rather than the plugin, the bottleneck is origin speed. We recommend xCloud there, and it is ours: xCloud and WPDeveloper are both Startise companies. Our [server compatibility guide](https://xspeedcache.com/docs/server-compatibility/) covers what each stack allows.

## Common Mistakes With Cache Warming

- 📉 **Reading a falling hit rate as a stalled warmer.** Different measurements. If the number moved but the queue is healthy, start with [the hit rate dropped overnight](https://xspeedcache.com/blog/cache-hit-rate-dropped/).
- 🔁 **Cutting the cache lifetime to keep things fresh.** It shortens the race without speeding up the runner, turning a finishing lap into an endless one.

## Frequently Asked Questions

### My preloader has shown 0 of 0 for three days. Is it broken?
Probably not broken, probably empty. Check whether the sitemap returns 200 to an anonymous request, then whether search engines are discouraged under Settings, Reading.

### I turned the cache lifetime down to one hour and now it never finishes. Why?
The lap got no faster and the deadline got shorter. Run the walk test above, then set the lifetime above one lap.

### I enabled the crawler in LiteSpeed Cache and nothing happened.
Its FAQ states the crawler must be enabled on the server side first. On shared hosting that is a support ticket, not a setting.

### My cache warms fine but visitors still get a slow first byte.
Warming is not your constraint then. Nearly half of sites have very little server time for a cache to take, which [when not to use a caching plugin](https://xspeedcache.com/blog/when-not-to-use-caching-plugin/) measures across 886 of them.

### Do I need a paid plugin to fix this?
No. Every check here is WP-CLI, a sitemap fetch and a response header. Our preloader is free in [xSpeed Cache](https://wordpress.org/plugins/xspeed/); [Free vs Pro](https://xspeedcache.com/free-vs-pro/) shows where the line falls.

## Finish the Lap, Then Leave It Alone

**What to do this week:**

1. Run the two commands above and write down the queue length and the scheduler's next run.
2. Divide your real URL count by your observed warm rate, compare it to your cache lifetime, and raise the lifetime first if the lap is longer.
3. Move WP-Cron to a system cron if the site is quiet, then recheck. If you want the warning built in rather than remembered, xSpeed Cache is free and Pro starts at $29 a year with a 14-day money-back guarantee: see [features](https://xspeedcache.com/features/) or [pricing](https://xspeedcache.com/pricing/).

A preloader that finishes a lap inside the cache lifetime needs no attention at all. That is the state to aim for, and the walk test tells you when you reached it.
