Ahosting Logo
Knowledge Base

Understanding WordPress Caching Layers

Four layers, and what each one actually storesBrowser cachethe visitor own copy of assetsPage cachethe finished HTML, which is the big winObject cachequery results, which is what helps logged-in pagesOPcachecompiled PHP, which helps everything and needs no pluginCart, checkout, account and any logged-in page must never be page-cached, which is exactly where the object cacheearns its place.

Caching means keeping the result of expensive work so it does not have to be repeated. In WordPress there are several kinds, they operate at different points, and confusing them is why people install three plugins and see almost no improvement.

Understanding which layer does what tells you which one is missing.

Page caching: the one that matters most

Without it, every visit runs PHP, queries the database, and assembles the page from scratch. With it, the finished HTML is stored and served directly.

The difference is not incremental. A page served from cache skips the application entirely, which on shared hosting also means it does not occupy one of your limited concurrent PHP processes, so caching improves capacity as much as speed. Monitoring your hosting resources walks through that ceiling.

If you do one thing, do this one.

Server-level or plugin

Page caching at the web server is faster than a plugin, because the request never starts PHP at all. A plugin has to load part of WordPress to decide the page is cached.

If your hosting offers server-level caching, use it and skip the caching plugin. Running both produces two layers with different ideas about when to clear, and the symptom is a change that appears for some visitors and not others.

What must never be cached

This is where caching causes real damage rather than merely failing to help.

Cart and checkout pages. Account pages. Anything showing information specific to one person.

Cache one of those and a visitor can be served another person's page. Their cart, their address, in some configurations their order history. Every serious caching setup excludes them by default, and every custom exclusion rule you write is an opportunity to break that.

If you run a shop, verify the exclusions rather than trusting them. There is more on the specifics in WooCommerce speed optimization.

Object caching, for the database

Page caching does nothing for logged-in users, because their pages differ. Object caching helps there: it stores the results of database queries in memory so repeated queries are not repeated.

WordPress caches objects within a single request by default. A persistent object cache (Redis or Memcached) keeps them between requests, which is where the gain is.

This matters most on sites with many logged-in users, a busy admin area, or an application-like front end. On a brochure site served almost entirely from page cache, it adds very little.

Opcode caching, already on

PHP compiles your code on every request unless the compiled form is cached. OPcache does that, and it is enabled by default on any current server.

You do not configure it and you do not need a plugin for it. It is worth knowing only because it explains why a code change sometimes takes a moment to appear.

Browser caching: for returning visitors

Headers telling the browser how long to keep images, CSS and JavaScript. A returning visitor then loads them from their own disk rather than from you.

This does nothing for a first visit, which is why it looks disappointing in testing and matters in reality. Most sites have a lot of returning visitors.

Set long expiry times for versioned assets, and make sure your theme's files carry a version so a change produces a new URL. Otherwise a returning visitor keeps the old stylesheet for a month. Compression and cache headers walks through setting them.

A CDN, caching somewhere else

A content delivery network stores copies near your visitors. It reduces distance, which matters when your audience is far from your server, and it absorbs traffic that would otherwise reach you.

It is a further layer instead of a replacement, and it introduces the same purge problem as any other: a change on your server does not reach the CDN until something clears it.

The clearing problem

Every layer is a place a stale version can hide, and the number of layers is why "I changed it and nothing happened" is so common.

When a change does not appear, work outward: browser first, in a private window; then the plugin or server cache; then the CDN. Checking in the same browser you have been using proves nothing.

Most caches clear the relevant pages automatically when you publish a post. Almost none of them clear reliably when you edit a theme file, a widget, or a menu. That is the case where you clear manually.

What caching cannot fix

Being honest about this saves people from installing a fourth plugin.

It does not make the admin area faster, because those pages are not cached. It does not help logged-in users on the front end for the same reason. It does not reduce the size of oversized images. A cached page still sends the same four-megabyte photograph, and optimizing images is the fix for that.

And it hides slow code rather than fixing it. A plugin taking three seconds still takes three seconds for every uncached request, including the first visitor to every page after each purge.

A sensible arrangement

Page caching at the server if available, otherwise one plugin. Browser caching headers set properly. Object caching if you have many logged-in users, and not otherwise. A CDN if your audience is geographically spread.

That is one of each layer, doing one job. Adding a second of anything is where the confusion starts.

Work out which layer answered

With four caches in a stack, the first diagnostic question is which one produced the response, and the headers say so.

curl -sI https://example.com/ | grep -iE 'x-cache|cf-cache-status|x-litespeed-cache|age|x-proxy-cache'
curl -sI -H 'Cookie: wordpress_logged_in_x=1' https://example.com/ | grep -iE 'x-cache|cf-cache-status'
curl -sI 'https://example.com/?nocache=1' | grep -iE 'x-cache|cf-cache-status'

Compare the three. A hit on the first and a miss on the second is correct, since logged in visitors must not be served a shared copy. A hit on the third means the query string is being ignored in the cache key, which can be deliberate and can also mean two different pages share one cached copy.

Doing this before changing any setting saves the common mistake of clearing a plugin cache repeatedly while the CDN in front keeps serving the old page.

What a purge does to the server behind it

Clearing everything at once is not free. Every subsequent request has to be built from scratch, all at the same time.

On a busy site that produces a spike of simultaneous work, and a machine that copes comfortably at a normal hit rate can fall over in the minute after a full purge. The symptom is a site that breaks immediately after a routine content update, which nobody connects to the purge.

uptime; ss -tn state established | wc -l

Two habits avoid it. Purge only what changed rather than everything, which most caches support by path or by tag. And where a full clear is unavoidable, do it at a quiet hour and warm the important pages afterwards by requesting them yourself. Measuring page speed properly covers the cold and warm difference.

The cache key is where privacy accidents happen

A cache decides which requests may share a stored copy, and a key that omits something important serves one visitor's page to another.

The dangerous omissions are the ones tied to identity or context: the logged in cookie, a currency or language selection, a country based variation, and anything that renders a name or a basket into the page.

curl -s https://example.com/ | grep -icE 'logged in as|my account|basket|cart total'
curl -sI https://example.com/ | grep -i vary

If a page containing personal text is ever cached publicly, the next visitor sees it. The Vary header is how a cache is told which request properties change the response, and its absence on a page that does vary is the fault to look for.

The safe arrangement is to exclude the pages that carry identity entirely, and to keep personal content out of pages that are cached at all. Why carts and sessions break with caching deals with the shop case.