Skip to content
WordPress6 min read

WordPress Caching Layers Explained: Page, Object, Opcode, CDN

The four caching layers that sit between your visitors and your database, what each one actually does, and how to make them work together instead of fighting.

Most WordPress performance conversations collapse every kind of caching into one vague concept, which is how sites end up with three caching plugins, a CDN, and a server that is still slow. There are four distinct layers, each solving a different problem at a different point in the request. Understanding what each one does is the difference between a fast site and a fragile one.

Page caching: the biggest single win

Page caching stores the fully rendered HTML of a request and serves it to the next visitor without touching PHP or MySQL at all. For anonymous traffic, which is most traffic on a content site, this is comfortably the largest performance gain available. It can be done by a plugin writing static files, but our strong preference is to do it at the web server, where a cache hit costs almost nothing.

nginx
fastcgi_cache_path /var/cache/nginx levels=1:2
    keys_zone=WORDPRESS:100m inactive=60m;

server {
    set $skip_cache 0;
    if ($request_method = POST) { set $skip_cache 1; }
    if ($http_cookie ~* 'wordpress_logged_in') { set $skip_cache 1; }

    location ~ \.php$ {
        fastcgi_cache WORDPRESS;
        fastcgi_cache_valid 200 10m;
        fastcgi_cache_bypass $skip_cache;
        fastcgi_no_cache $skip_cache;
    }
}

The rules that matter are the bypass conditions: never cache POST requests, never cache logged-in users, and make sure carts, checkouts and account pages are excluded on any e-commerce site. Most page cache incidents we are called in to fix come down to one of those three being wrong.

Object caching: for the pages you cannot cache

Logged-in users, personalised pages and the admin itself all bypass the page cache, and that is where object caching earns its place. WordPress already caches database results in memory for the duration of a single request; a persistent object cache backed by Redis or Memcached keeps those results between requests. Expensive queries, options lookups and transients stop hammering MySQL on every page view.

This is the layer that transforms WooCommerce stores and membership sites, where page caching covers a minority of traffic. It needs a drop-in plugin and a Redis service, and it needs monitoring: a full Redis instance that starts evicting keys can produce genuinely confusing bugs.

Two checks tell you whether the layer is earning its keep: the hit ratio reported by the drop-in or by Redis itself, and the query count on a busy page before and after. A stubbornly low ratio usually means some plugin is generating unique cache keys per request, which quietly turns a cache into a memory leak with extra steps.

OPcache: the layer everyone forgets

Every request that does reach PHP has to run your plugin and theme code, and without OPcache, PHP recompiles every file from source each time. OPcache keeps the compiled bytecode in shared memory, and on a typical WordPress install with dozens of plugins the saving is substantial. It ships with modern PHP and is usually enabled, but often with default memory limits that are too small for a large codebase, so check opcache.memory_consumption and the hit rate rather than assuming.

The CDN: caching at the edge

A CDN moves cached responses physically closer to visitors. At minimum it should serve your static assets: images, CSS, JavaScript and fonts. The bigger win is edge-caching full HTML for anonymous visitors, which services like Cloudflare can do with cache rules keyed on the WordPress login cookie. That effectively gives you a page cache in dozens of locations worldwide, but it demands the same discipline about bypass conditions, plus a reliable purge hook so published changes appear promptly.

Making the layers cooperate

The layers stack rather than compete: CDN in front, page cache at the origin, object cache behind that for dynamic requests, OPcache under everything. The classic mistake is running two tools at the same layer, such as a caching plugin writing pages while nginx caches them again, which makes invalidation nearly impossible to reason about. Pick one tool per layer, wire the purges together, and test invalidation as carefully as you test the caching itself.

If your WordPress site is slow and you are not sure which layer is missing, STRCLI can audit it and tell you exactly where the time is going.

Start your project

Have an idea? Let's ship it together.

Tell us what you're building — we'll reply within one business day with an honest take and a clear next step.