WordPress

Your Site Only Feels Fast Because You Cached It: A WordPress Caching Guide

9 min read

Here’s a strange thing about running a WordPress site: the person least likely to notice it’s slow is you. You visit the same pages all day, your browser has them stashed locally, the server has them warm, and everything snaps into place. Meanwhile a first-time visitor on a phone waits three seconds for the same homepage — and half of them are gone before it finishes painting.

Caching is the set of tricks that closes that gap. It’s the single highest-leverage speed win most WordPress sites are leaving on the table, and it’s also the thing that quietly breaks in the most confusing ways. A site we took over last year was serving a stale homepage that still advertised a sale which had ended three weeks earlier, because a page-cache plugin and a CDN were both holding their own copy and nobody knew which button actually purged it.

This guide walks through what caching really is, the five layers that stack up on a typical WordPress install, and how to reason about them when something goes wrong.


What Caching Actually Is

A cache is a saved copy of expensive work, kept somewhere fast so you don’t redo it. Every time someone loads an uncached WordPress page, PHP boots up, runs your theme and plugins, fires off a dozen or more database queries, assembles the HTML, and hands it back. That whole dance can take hundreds of milliseconds — and it produces the exact same result for the next visitor a second later.

Caching says: do the expensive work once, store the answer, and serve the stored answer to everyone else until it goes stale. The tricky part isn’t storing the copy. It’s knowing when the copy is wrong and needs to be thrown away. That question — cache invalidation — is where nearly every caching headache comes from.

WHY IT MATTERS

Time to First Byte — how long the server takes to start sending a response — feeds directly into Largest Contentful Paint, one of Google’s Core Web Vitals. Page caching is the most direct lever you have on it, often turning a 600ms server response into 50ms. Faster pages keep visitors around and give you a real ranking edge.

The Five Layers, From the Browser Back to the Database

People say “add caching” like it’s one switch. On a real WordPress stack there are at least five distinct layers, each caching something different, each with its own way to clear it. Understanding which layer holds a stale copy is most of the battle.

1. Browser cache

The visitor’s own browser stores your CSS, JavaScript, fonts, and images on their disk so the next page view doesn’t re-download them. You control this with HTTP response headers — Cache-Control and Expires — that tell the browser how long a file is good for. A logo that changes maybe once a year can safely be cached for months, which is why asset URLs often carry a version string: change the URL and you force a fresh download.

2. CDN / edge cache

A content delivery network like Cloudflare or Bunny keeps copies of your files on servers around the world, so a visitor in Sydney pulls your images from a nearby city instead of your origin server. By default a CDN caches static assets, but most can also do full-page caching at the edge — serving your entire HTML page from their network without ever touching your host. That’s blisteringly fast, and it’s also the layer people most often forget to purge.

3. Page cache

This is what most “caching plugins” mean. The first visitor triggers the full PHP-and-database render, and the finished HTML gets saved — usually as a flat file on disk. Every visitor after that gets the saved file, skipping PHP and MySQL almost entirely. WP Super Cache, W3 Total Cache, WP Rocket, and LiteSpeed Cache all live here. A logged-in user or someone with items in a cart normally bypasses the page cache so they don’t see someone else’s session.

4. Object cache

Object caching works one level deeper, inside WordPress itself. WordPress has a built-in WP_Object_Cache, but out of the box it’s non-persistent — it only remembers things for the duration of a single page load, then forgets everything. Drop a persistent backend like Redis or Memcached behind it and those cached database results survive between requests. This is the layer that helps dynamic, logged-in-heavy sites — WooCommerce stores, membership sites, busy dashboards — where a flat page cache can’t do much.

WordPress knows this matters. Since version 6.1, the Site Health screen will actively suggest adding a persistent object cache once your site does enough database work to benefit from one.

5. Opcode cache (OPcache)

The deepest layer isn’t really WordPress’s at all — it’s PHP’s. OPcache is a PHP extension that compiles your PHP source into bytecode once and keeps that compiled version in shared memory, so PHP doesn’t re-parse the same files on every single request. It’s on by default in modern PHP builds, and any decent host already has it running. You rarely touch it, but it’s worth knowing it’s there.

QUICK REFERENCE

Browser caches assets on the visitor’s device · CDN caches assets (and optionally full pages) at the edge · Page cache stores finished HTML on your server · Object cache stores database results between requests · OPcache stores compiled PHP bytecode. When something looks stale, work from the visitor’s browser back toward the database until you find the layer still holding the old copy.

Page Cache vs. Object Cache: Which Do You Need?

These two get confused constantly, and they solve different problems. Page caching stores the whole finished HTML page. It’s fantastic for content that looks the same for every anonymous visitor — a blog, a brochure site, a marketing page. If most of your traffic is logged out and reading the same posts, a page cache is the biggest win you can install, and often the only one you need.

Object caching stores the smaller pieces — the results of specific database queries — so WordPress can reuse them without re-querying. It shines exactly where page caching falls down: sites where most requests are personalized and can’t be served from a single frozen HTML file. A WooCommerce checkout, a member dashboard, a forum where everyone’s logged in. There, page caching mostly steps aside, and a Redis-backed object cache is what keeps the database from melting.

Most serious sites end up running both. Page cache handles the anonymous crowd, object cache handles everything dynamic underneath, and they don’t step on each other.

The Real Problem: Cache Invalidation

Storing a copy is easy. Knowing when to throw it away is the hard part, and it’s where the confusing bugs come from. You publish an edit, reload the page, and see the old version — because a cache somewhere is still handing out yesterday’s copy. The frustrating cases are when several layers each hold a stale version and clearing one doesn’t touch the others.

Good caching plugins invalidate automatically: publish or update a post and they purge that page (and related archives) for you. The failure mode is having caches your plugin doesn’t know about. Your page-cache plugin clears its files, but your CDN is still serving full-page HTML from its edge and has no idea you changed anything. That was the stale-sale-banner situation exactly — the WordPress-side cache was clean, and Cloudflare was cheerfully serving three-week-old HTML.

How to clear things, from WP-CLI

When you have terminal access, WP-CLI is the fastest way to flush caches without clicking through admin screens:

  • wp cache flush — flushes the entire object cache (Redis, Memcached, or the built-in one).
  • wp transient delete --all — clears all transients, WordPress’s own expiring cache stored in the options table (or in your object cache if one’s active).
  • Most page-cache plugins add their own command too, like wp rocket clean or wp w3-total-cache flush all.

If you’ve cleared every WordPress-side cache and still see a stale page, that’s your signal the copy is living outside WordPress — at the CDN or edge — and that’s where you purge next.

Transients: the cache you might already be using

WordPress ships a built-in caching tool many site owners never notice: the Transients API. A transient is a named piece of data with an expiration time — a plugin might cache the result of a slow external API call as a transient for an hour so it isn’t re-fetched on every page load. Without a persistent object cache, transients live in your wp_options database table. With Redis or Memcached in place, they move into fast memory automatically. It’s the same API either way, which is part of why adding an object cache can speed up plugins you didn’t even realize were caching.

A Sane Setup for a Typical Site

You don’t need all five layers tuned to perfection. For most small-business and content sites, a sensible baseline looks like this. Turn on a single page-caching plugin — running two at once is a classic way to create conflicts, so pick one. Put a CDN in front of your assets, and if it offers full-page caching, learn where its purge button is before you turn it on, not after. Make sure your host has OPcache enabled (nearly all do). Add a persistent object cache only if your site is genuinely dynamic or your Site Health screen asks for it — a simple brochure site won’t notice the difference.

The mistake we see most often isn’t too little caching. It’s stacking redundant plugins and half-configured CDNs until nobody can explain why an edit takes twenty minutes to appear. Fewer, well-understood layers beat a pile of overlapping ones every time.

FIELD-TESTED TIP

When you’re debugging a “why isn’t my change showing up” problem, test in a private/incognito window. That instantly rules out your own browser cache and any logged-in bypass, so you see what a real anonymous visitor sees — which is usually what the caches are actually serving.

Frequently Asked Questions

Often not. Many managed WordPress hosts run their own server-level page cache, in which case adding a second page-caching plugin can cause conflicts rather than help. Check what your host provides first. If they handle page caching, you may only want a plugin for extra features like asset minification, and you should avoid running two page caches at once.

Page caching stores the entire finished HTML of a page and serves that saved copy to anonymous visitors, skipping PHP and the database. Object caching stores smaller pieces — the results of individual database queries — so WordPress can reuse them across requests. Page caching is best for mostly-static, logged-out traffic; object caching helps dynamic, logged-in-heavy sites where a single frozen HTML file won’t work. Many sites run both.

A cache somewhere is still serving the old copy. Work from the visitor’s browser back toward the database: clear your own browser cache (or use an incognito window), then purge your page-cache plugin, then purge your CDN if it does full-page caching. Most caching plugins clear the relevant page automatically when you update a post, but a CDN edge cache usually will not unless you configure it to, which is why edits can appear to linger.

Yes. WordPress has a built-in object cache (WP_Object_Cache) that reuses data within a single page load, plus the Transients API for storing data with an expiration time. Without a persistent backend like Redis or Memcached, the object cache is cleared at the end of every request and transients are stored in the database. Adding a persistent object cache lets both survive between requests and moves transients into fast memory.

Use WP-CLI. Run “wp cache flush” to flush the object cache and “wp transient delete –all” to clear all transients. Most page-cache plugins add their own command as well, such as “wp rocket clean” or “wp w3-total-cache flush all”. Remember that these only clear WordPress-side caches — if a stale page persists afterward, the copy is at your CDN or edge cache and must be purged there.

It can cause visible glitches if misconfigured. The most common issues are caching pages that should stay dynamic — like a cart, a checkout, or a logged-in dashboard — so visitors see stale or another user’s data, and running two page-cache plugins that fight over the same files. Good plugins exclude dynamic and logged-in pages by default. Stick to one page-cache layer, exclude anything personalized, and know how to purge each layer, and caching is safe.

Caching is one of those things that’s invisible when it works and maddening when it doesn’t. Map your layers once, learn where each purge button lives, and it stops being a mystery.

Built by amplifi.studio — see also The Slow-Site Tax: How to Fix WordPress Core Web Vitals.