WordPress caching: page, object and browser caches
WordPress does not cache finished pages by itself. The five layers of caching, how WordPress tests for them, what to leave out, and how to check each one works.
In this guide
Why WordPress needs a cache
For each visit, WordPress runs PHP code from the core, the theme and every active plugin. It asks the database many questions and builds the page. The WordPress Advanced Administration Handbook says that without a caching solution, performance slows to a halt as more requests stack up, which often crashes the web or database server.
Caching means keeping the result of that work and reusing it. The Handbook says that a page cache, which saves posts and pages as static files, can improve performance several hundred times over for fairly static pages. That is the handbook's claim about its own method, not a measurement of your site, but it explains why caching is the first thing to add. See caching explained for the general idea.
The five layers
| Layer | What it saves | Where it lives | Who usually sets it up |
|---|---|---|---|
| Opcode cache (PHP OPcache) | Re-reading and compiling PHP files on every request | In the server's memory | Your host |
| Page cache | The whole finished page, so PHP and the database are not used | Static files on disk, in memory, or in a server in front of WordPress | Your host, or one plugin |
| Object cache | Database results and settings that WordPress asks for again and again | A cache server such as Redis or Memcached, or the PHP process | Your host, plus a plugin file |
| Browser cache | Files the visitor has already downloaded | The visitor's device | Headers from your server |
| CDN | Copies of files, and sometimes pages, close to the visitor | A network of servers | A CDN service |
Each layer does a different job, so they add up. A page cache does not replace an object cache, and the reverse is also true.
Which layers to start with
This is a judgment based on how each layer works, not a rule from the sources:
| Your site | Start with | Add when needed |
|---|---|---|
| A brochure site or a blog that changes rarely | A page cache, and correct file headers | A CDN, if visitors are far from the server |
| A store, a membership site or a booking site | A page cache with personal pages left out, and a persistent object cache | A CDN for files |
| A site with heavy traffic or many editors | All of the layers, set up by your host or a developer | A CDN that can also keep pages |
Opcode cache
WordPress is written in PHP. An opcode cache keeps the compiled form of each PHP file in memory. WordPress's own Site Health text says it stores precompiled script bytecode in memory and reduces the need for PHP to load and parse scripts on each request. In recent WordPress code there is a Site Health test for it, with the label "Opcode cache is not enabled" when it is off.
This is a server setting, not a WordPress one. Ask your host whether OPcache is on. Most current hosts switch it on already.
Page cache
The page cache is the layer with the largest effect for most sites, and WordPress core does not provide one. It provides the hook: when the constant WP_CACHE is true and the file wp-content/advanced-cache.php exists, WordPress loads that file very early. A caching plugin installs the file. A host's cache works at the server instead, so your site may be cached with no plugin. A CDN can also keep the page cache in its own data centers; see Cloudflare APO for WordPress.
How WordPress tests for it
Since WordPress 6.1 the Site Health screen has a Page cache test. According to the core source, it:
- makes three requests to the home page, as a visitor who is not logged in;
- looks for a page cache plugin (the file and constant above), and for caching headers in the replies:
Cache-Controlwith amax-ageabove zero, a futureExpires, anAgeabove zero,Last-Modified,ETag,Via, and cache-hit headers that some hosts and CDNs add, such asX-Cache,CF-Cache-StatusandX-Varnish; - takes the median response time of the three requests.
The result depends on a threshold of 600 milliseconds, which the code takes from web.dev's guidance on time to first byte:
- Good: a cache was found and the median response was under 600 milliseconds.
- Recommended: no cache was found, but the site is fast.
- Critical: the site is slower than that.
Treat it as a hint. The test counts the mere presence of headers such as ETag or Last-Modified, which a server can send without caching the page. Use the checks later in this guide to be sure.
What to set
- Use one page cache. Your host's cache or one plugin, not two. Two systems that save and serve pages interfere with each other.
- Serve saved pages to visitors who are not logged in. A logged-in visitor sees different pages, so most caches skip them. Check that yours does.
- Leave out the personal pages. The cart, checkout and account pages must never be saved and shown to someone else. Stores need extra care here; see WooCommerce speed.
- Clear it when content changes. Publishing or updating a page should clear the saved copy of that page and the lists it appears in. Test it.
- Refresh pages with forms in time. WordPress's security tokens (nonces) are valid for between 12 and 24 hours by default, according to the core source. A cached form page that is older than that will carry a token that no longer works. Keep the cache lifetime under 12 hours for pages with forms, or clear them on a schedule.
- Ignore tracking parameters. Addresses that differ only by a campaign tag should be served from the same saved copy.
- Warm the cache. Some systems rebuild the most important pages after a clear, so the first visitor does not wait.
Object cache
WordPress asks the database for the same things on every request, such as its settings. The core class that stores them is called the object cache. By default the cache holds data only while one page is being built. A persistent object cache keeps it between requests in a cache server.
The Handbook explains the effect. Without a persistent cache, the server reads the site's options from the database for every page view. Those trips slow the server's response, and on a busy day they can overwhelm the database. It adds that cached data should be replaceable: if the cache is lost, the site still works and rebuilds it, only more slowly.
To use one, your host needs to run a cache server, and WordPress needs a plugin file named object-cache.php in the content folder that talks to it. The Site Health test looks for these services: APCu, Redis, Relay, Memcache and Memcached.
Transients and the object cache
WordPress has a way for plugins to save a value for a limited time, called a transient. The wp-config handbook page explains where it goes. When a persistent object cache is active, transients can live in it. Without one, they are written to the database, typically in the wp_options table. Heavy use of transients on a site without a persistent cache can therefore add database reads and writes and make the options table grow. The handbook adds that transients saved with an expiry are not loaded on every request, while ones without an expiry are.
Do you need one?
WordPress suggests a persistent object cache in Site Health when any of these is true:
- the site is a Multisite network;
- there are more than 500 autoloaded options, or they total more than 100,000 bytes;
- any of the comments, options, posts, terms or users tables has at least 1,000 rows.
A small brochure site with a page cache can do without. A store, a membership site, or a site with many plugins is the usual case for one. When it is working, Site Health reports that a persistent object cache is being used.
Three common misunderstandings
The same handbook page lists these:
- Setting
WP_CACHEto true does not turn caching on by itself. It only makes WordPress look for theadvanced-cache.phpfile. - A persistent object cache and a page cache are separate systems. The object cache can work without
WP_CACHE. WP_CACHEdoes not switch on Redis, Memcached or browser caching.
Browser and CDN caches
These are covered in other guides. In short, the browser cache depends on headers: long lifetimes for files that have a version in the name, and checks for the page itself. See HTTP caching headers. A CDN keeps copies close to your visitors, and with the right settings it can keep whole pages too. See what is a CDN.
One warning applies to every layer. If a plugin or host sends Cache-Control: no-store on public pages, shared caches and the browser's back/forward cache will not keep them. See the back/forward cache.
How to check each layer
Page cache. Open a page in a private window, so you are logged out. In DevTools, open the Network panel, reload, and select the first request, the page itself. Look at the response headers for signs of a cache: Age, X-Cache, CF-Cache-Status or a header your host documents. Reload twice more. The server response time of the cached copies should be much lower than the first. If it is not, the page is probably not being cached. The server response time guide shows how to measure it.
Here is what the difference can look like. These headers are an illustration, not output from a real site, and the names depend on your cache:
# First request after a clear: built by WordPress
cache-control: max-age=0, s-maxage=3600
x-cache: MISS
# Second request: served from the cache
cache-control: max-age=0, s-maxage=3600
age: 38
x-cache: HITAge is the standard header that says how many seconds a shared cache has held the copy. X-Cache is one of the names that Site Health knows, and other caches use other names. Your host's documentation says which one yours uses.
Logged-out and logged-in. Add a product to the cart, or sign in on a test account, and make sure the page changes for you and not for the next visitor. This is the check that protects your customers.
Clearing. Edit a post, save it, and reload it in the private window. The change should appear at once. Do the same for a change on the home page.
Object cache. Open Tools, then Site Health, then the Status tab. Look for "A persistent object cache is being used".
Opcode cache. In recent WordPress versions, Site Health has a test for it. If you do not see one, ask your host.
Mistakes to avoid
- Two page caches. A host cache and a plugin cache, or two plugins.
- Saving personal pages. The worst outcome of a cache is a customer seeing another customer's cart or account.
- Never clearing. Old prices and old stock are the usual symptom.
- Treating Site Health as proof. A green result can come from headers alone.
- Switching on every option. Features that combine, delay or rewrite scripts can break pages. Turn them on one at a time and test.
- Forgetting the CDN. A page can be cleared in WordPress and still be served from the CDN. Clear both.
Check your own page
Run the free audit and look at Document request latency. If the server response line fails, a page cache is the first thing to add or fix. If it passes, your cache may already be working, and the next steps are the theme and plugins.
Sources
- Optimization and Cache in the WordPress Advanced Administration Handbook: the kinds of cache and the effect of a persistent object cache.
- Editing wp-config.php in the same handbook: the cache constants, the layers, transients and the common misunderstandings.
- WordPress core: Site Health: the page cache, persistent object cache and opcode cache tests, their headers and thresholds.
- WordPress core: wp-settings.php, load.php and pluggable.php: how the
advanced-cache.phpandobject-cache.phpfiles are loaded, and how long nonces last.
Start here
Free website audit
Live Google data for any public page: mobile and desktop.
Mobile + desktop · Lighthouse lab test · Real-user Chrome data when Google has it
Rather have this done for you? WordPress speed · Book a call