Blog · Guides

WordPress Caching Layers Explained: Browser, Edge, Page, Object, OPcache

Most WordPress performance advice tells you to “just install a caching plugin” and move on. That advice is not wrong, but it is incomplete. Caching is not a single switch. It is a stack of independent layers, each one intercepting requests at a different point in the journey from a visitor’s browser to your database. Enable them in the right order and their benefits multiply. Enable them in the wrong order and you spend hours troubleshooting cache conflicts you did not know were possible.

This guide walks you through every caching layer in a modern WordPress stack, what problem each one solves, and how to think about them together.

The Mental Model: A Request’s Journey

When a visitor loads a page on your site, a request travels outward from their device and inward toward your server. At each stage, a cache can intercept that request and serve a stored response instead of letting it go further. The further inward a request travels, the more work your server has to do. Stopping it early is always cheaper.

Here is the journey, outermost to innermost:

  1. Browser cache (on the visitor’s device)
  2. Edge cache (on a CDN like Cloudflare)
  3. Full-page cache (on your web server)
  4. Object cache (in memory, close to PHP)
  5. OPcache (inside PHP itself)

Below each database query sits at the very end, reached only when every cache above it has missed. Your goal is to make that happen as rarely as possible.

Layer 1: Browser Cache

The browser cache lives entirely on the visitor’s device. When a browser downloads a stylesheet, a script, or an image, it can store that asset locally. On the next visit, if the asset has not expired, the browser serves it from disk without making any network request at all.

You control browser caching through HTTP response headers, primarily Cache-Control and Expires. A typical rule for static assets looks like this:

Cache-Control: public, max-age=31536000, immutable

That tells the browser to keep the file for one year without checking the server again. For HTML pages you generally want a much shorter or zero cache time, because page content changes and you want visitors to see updates quickly.

Most WordPress caching plugins set browser cache headers for static assets automatically. If you are configuring a server directly, add rules in your .htaccess (Apache) or your LiteSpeed server config. The key trade-off here is freshness versus savings: longer cache times save bandwidth and latency, but they also mean visitors can see stale assets if you update a file without changing its URL. Version-stamped filenames, which WordPress core and most build tools generate automatically, solve this cleanly.

Layer 2: Edge Cache (CDN)

An edge cache sits geographically between your visitor and your origin server. A service like Cloudflare operates data centers around the world. When a visitor in Tokyo requests a page from your London-based server, Cloudflare can serve a cached copy from its nearest point of presence instead, reducing round-trip time dramatically.

Beyond raw speed, running traffic through an edge network gives you a WAF, bot mitigation, DDoS protection, Universal SSL, and HTTP/3 without any configuration on your origin server. One important security detail: if you route traffic through Cloudflare, keep your origin server’s IP address unpublished. An attacker who discovers the real IP can bypass the edge network entirely and attack your server directly, removing all of those protections.

Edge caches are excellent for static assets and can cache full HTML pages for logged-out visitors. You configure caching behavior through your CDN’s rules, controlling which URLs get cached, for how long, and under what conditions cached copies should be purged. Most serious caching plugins include integration that triggers an edge cache purge whenever you publish or update content.

Layer 3: Full-Page Cache

Full-page caching is what most people mean when they say “WordPress caching.” When a logged-out visitor requests a page, the server generates a complete HTML response, stores it to disk or memory, and serves that stored copy to all subsequent visitors requesting the same URL. PHP and your database are bypassed entirely for those cached requests.

This is the single highest-impact cache layer for a typical WordPress site with anonymous traffic. A page that previously required fifty database queries and several hundred milliseconds to render is now served in single-digit milliseconds.

On a LiteSpeed or OpenLiteSpeed server, the free LiteSpeed Cache plugin handles full-page caching at the server level, which is faster than PHP-level caching because LiteSpeed serves cached pages before PHP even starts. On other server stacks, plugins like W3 Total Cache or WP Rocket write cached files that Apache or Nginx can serve directly.

The main thing to configure carefully is cache exclusions. Pages like the cart, checkout, account dashboard, and any URL that reflects a logged-in user’s state must be excluded from the full-page cache. Serving a cached page containing another user’s data is a real and serious bug. Most caching plugins handle the common cases automatically, but always verify exclusions after setup.

Layer 4: Object Cache

WordPress has a built-in object cache that stores the results of database queries in memory during a single request. By default this in-memory store is thrown away when the request ends, meaning the next request has to run the same queries all over again.

A persistent object cache changes that. By dropping in a Redis or Memcached integration, you keep those query results in memory across requests. When WordPress asks for the list of active plugins, the current site options, or the results of a complex WP_Query, it finds the answer in Redis in microseconds instead of hitting the database.

Object caching matters most for sites that cannot fully cache pages: WooCommerce stores where every session is unique, membership sites, or any page that must be generated dynamically for logged-in users. For those sites, object caching can be the difference between a usable site and a painfully slow one.

To connect WordPress to Redis, install a drop-in file at wp-content/object-cache.php. Plugins like Redis Object Cache handle this for you and provide a status dashboard inside wp-admin. Once connected, you can inspect cache hit rates with wp-cli:

wp redis status

A healthy Redis setup should show a high hit rate on repeat requests. A persistently low hit rate usually means your cache keys are being invalidated too aggressively or your TTL is too short.

Layer 5: OPcache

OPcache works at the PHP level and is invisible to WordPress itself. Every time PHP runs a .php file, it normally reads the file from disk, parses it, and compiles it to bytecode. OPcache stores that compiled bytecode in shared memory. On subsequent requests, PHP skips the read-parse-compile cycle entirely and executes from the cached bytecode.

For a WordPress installation with hundreds of PHP files across core, themes, and plugins, OPcache provides a consistent baseline speedup on every single request, cached or not. It is not a substitute for page caching. It is a multiplier that makes everything PHP does faster.

OPcache ships with PHP and is enabled by default in most production environments. On PHP 8.3, the current solid default recommendation, you can verify it is active with:

php -r "echo opcache_get_status() ? 'enabled' : 'disabled';"

Key settings to review in php.ini:

  • opcache.memory_consumption: the memory pool for cached bytecode. 128 MB to 256 MB is typical for a WordPress site with many plugins.
  • opcache.max_accelerated_files: the maximum number of files OPcache will track. Set this higher than your total PHP file count to avoid silent cache misses.
  • opcache.validate_timestamps: set to 0 in production for best performance, but then you must reload PHP-FPM after deploying code changes to clear stale bytecode.

The Right Order to Enable Them

Enabling caching layers in sequence makes testing and troubleshooting far easier than turning everything on at once.

  1. OPcache first. It has no configuration in WordPress and is almost always safe to enable. Confirm it is active and sized correctly. Every subsequent test now reflects PHP’s true performance.
  2. Object cache second. Install Redis and its drop-in, then use wp-cli to verify connectivity. Run a few logged-in page loads and check that hit rates climb. This isolates any database bottlenecks.
  3. Full-page cache third. Configure your caching plugin, set your exclusions carefully, then test cached and uncached responses with curl -I to confirm the right pages are being served from cache. Check the X-Cache or similar header in the response.
  4. Edge cache fourth. Point your CDN at the origin, configure cache rules, and verify that static assets are served from edge nodes. Test a purge workflow by updating a post and confirming the cached copy refreshes.
  5. Browser cache last. Review your Cache-Control headers for static assets and confirm they match your deployment strategy for cache-busting.

After each layer, measure with PageSpeed Insights or Lighthouse. Core Web Vitals give you concrete targets: LCP at or below 2.5 seconds, INP at or below 200 milliseconds, CLS at or below 0.1. Compare lab data and field data separately, since they measure different things and can diverge significantly.

Takeaway

Caching is not one thing. It is five distinct layers, each solving a different part of the latency problem. OPcache makes PHP faster. Object caching saves database queries. Full-page caching bypasses PHP entirely. Edge caching moves content closer to your visitors. Browser caching eliminates the network request altogether. Enable them in order, test at each step, and the wins compound in ways that no single plugin or configuration tweak can match on its own.