
What is caching in WordPress and how does it work?
Caching in WordPress means storing a ready-made copy of something that took work to create, such as a full HTML page, the result of a database query, or compiled PHP code, so it can be reused on the next request instead of being built again from scratch. Because WordPress normally runs PHP and database queries on every page view, caching can reduce server load dramatically and make pages load much faster for your visitors.
Caching isn't one single feature. It happens in several layers, from the visitor's browser all the way down to your server's PHP engine, and each layer solves a different problem. In this article, you'll learn how WordPress builds a page without caching, what each caching layer does, how they work together, which tools to use, and how to avoid the common problems caching can cause.
How WordPress Builds a Page Without Caching
To understand why caching matters, it helps to see what happens on an uncached request:
-
The request arrives: A visitor's browser asks your server for a URL, such as
/blog/my-post/. -
PHP loads WordPress: The web server hands the request to PHP, which loads WordPress core, your active theme, and every active plugin.
-
Database queries run: WordPress reads your settings from
wp_options, works out what content was requested, and queries the database for the post, its metadata, categories, menus, widgets, and more. A typical page can run dozens of queries, and complex plugins can push that into the hundreds. -
HTML is generated: Your theme's templates and blocks combine all that data into an HTML page.
-
The response is sent: The finished HTML goes back to the browser, which then requests CSS, JavaScript, fonts, and images.
This process might take anywhere from a fraction of a second to several seconds, depending on your hosting, theme, and plugins. The important thing is that for most visitors, the result is exactly the same page the previous visitor saw. Caching avoids repeating all that work.
Why Caching Matters
Caching delivers benefits that are easy to feel:
- Faster pages: Serving a stored HTML file is much quicker than running PHP and database queries, which improves Time to First Byte (TTFB) and Core Web Vitals.
- Lower server load: Your server can handle many more visitors with the same resources, which helps during traffic spikes.
- Better resilience: A cached site is less likely to slow to a crawl or crash when a post goes viral.
- Lower hosting costs: Efficient sites can often stay on smaller plans for longer.
The Different Types of WordPress Caching
Think of caching as a series of layers. A request passes through them from the outside in, and the first layer that has a valid copy answers it.
Browser Caching
Browser caching happens on the visitor's device. When a browser downloads your CSS, JavaScript, fonts, and images, your server can send headers like Cache-Control that tell the browser how long to keep them. On the next page view, the browser reuses its local copy instead of downloading the file again.
This makes repeat visits and navigation between pages much faster. WordPress adds version query strings like style.css?ver=6.8 to enqueued files, so when a file changes, its URL changes and browsers fetch the new version.
On Apache servers, you can set browser caching in .htaccess (back it up first):
<IfModule mod_expires.c>
ExpiresActive On
ExpiresByType image/webp "access plus 1 year"
ExpiresByType image/avif "access plus 1 year"
ExpiresByType image/jpeg "access plus 1 year"
ExpiresByType image/png "access plus 1 year"
ExpiresByType image/svg+xml "access plus 1 year"
ExpiresByType font/woff2 "access plus 1 year"
ExpiresByType text/css "access plus 1 month"
ExpiresByType application/javascript "access plus 1 month"
</IfModule>
On Nginx, the equivalent goes inside your server block:
location ~* \.(css|js|woff2|webp|avif|jpg|jpeg|png|svg|ico)$ {
expires 30d;
add_header Cache-Control "public, max-age=2592000";
access_log off;
}
Most caching plugins can add these rules for you, and many managed hosts set them by default.
Page Caching
Page caching is the layer with the biggest impact. The first time someone visits a page, WordPress builds it normally, and the page cache saves the finished HTML. The next visitors receive that saved HTML directly, skipping PHP and the database almost entirely.
Page caching can happen in a few places:
- Plugin-level page cache: Plugins like WP Super Cache, W3 Total Cache, WP Rocket, WP Fastest Cache, and LiteSpeed Cache save HTML files to disk and serve them through PHP or, more efficiently, through server rewrite rules.
- Server-level page cache: Managed hosts often use Nginx FastCGI cache, Varnish, or LiteSpeed's built-in cache. These serve pages before PHP even starts, which is faster still.
- Edge page cache: A CDN such as Cloudflare (with APO or cache rules), Fastly, or a host's own edge network can store full HTML pages in data centers around the world.
Page caching works best for content that looks the same for everyone. It's typically bypassed for logged-in users, the WordPress admin, shopping carts, checkout pages, and pages with personalized content. Good caching plugins handle these exceptions automatically, especially for WooCommerce.
Object Caching
Object caching stores the results of database queries and other expensive computations in memory. WordPress has a built-in object cache API, with functions like wp_cache_get() and wp_cache_set(), which core uses constantly for posts, terms, users, and options.
By default, this cache is non-persistent. It only lasts for a single page request, which avoids repeating the same query within one page load but offers nothing for the next visitor.
A persistent object cache keeps those values in a fast in-memory store like Redis or Memcached, so they survive between requests. This is especially valuable for:
- Logged-in users, who usually bypass page caching.
- WooCommerce stores, membership sites, forums, and LMS platforms with lots of dynamic pages.
- The WordPress admin dashboard.
- Sites with heavy use of options and transients.
To use Redis, your host needs Redis installed, and you add an object cache drop-in file called object-cache.php to wp-content. The free Redis Object Cache plugin handles the drop-in for you. Tools > Site Health will even suggest a persistent object cache when your host supports one.
Here's how you might use the object cache in your own code, for example in a child theme's functions.php or a custom plugin:
function sajjad_get_popular_post_ids() {
$cache_key = 'sajjad_popular_post_ids';
$post_ids = wp_cache_get( $cache_key, 'sajjad' );
if ( false === $post_ids ) {
$post_ids = get_posts(
array(
'post_type' => 'post',
'posts_per_page' => 5,
'orderby' => 'comment_count',
'order' => 'DESC',
'fields' => 'ids',
)
);
wp_cache_set( $cache_key, $post_ids, 'sajjad', HOUR_IN_SECONDS );
}
return $post_ids;
}
Without a persistent object cache, this still works but only saves time within the current request. With Redis or Memcached installed, the result is shared across requests for an hour.
Transients
Transients are WordPress's API for caching data with an expiry time. They're similar to the object cache, but with a fallback: if there's no persistent object cache, transients are stored in the wp_options table, so they still persist between requests.
Transients are ideal for caching slow external API calls:
function sajjad_get_remote_stats() {
$stats = get_transient( 'sajjad_remote_stats' );
if ( false === $stats ) {
$response = wp_remote_get( 'https://api.example.com/stats' );
if ( is_wp_error( $response ) || 200 !== wp_remote_retrieve_response_code( $response ) ) {
return array();
}
$stats = json_decode( wp_remote_retrieve_body( $response ), true );
if ( ! is_array( $stats ) ) {
return array();
}
set_transient( 'sajjad_remote_stats', $stats, 12 * HOUR_IN_SECONDS );
}
return $stats;
}
To clear it manually, call delete_transient( 'sajjad_remote_stats' ). Keep in mind that the expiration is a maximum, not a guarantee. A transient can disappear earlier, so your code should always be ready to rebuild the data.
Opcode Caching
PHP is a compiled-on-demand language. Every time a PHP file runs, it has to be parsed and compiled into bytecode. OPcache, which is built into PHP, stores that compiled bytecode in memory so it's reused on later requests.
Since WordPress loads hundreds of PHP files per request, OPcache makes a big difference. It's enabled by default on almost every decent host running PHP 8.x, and you rarely need to touch it. You can confirm it in Tools > Site Health > Info > Server or ask your host.
CDN Caching
A Content Delivery Network stores copies of your static files, and optionally full pages, on servers around the world. A visitor in Sydney gets your images from a nearby server instead of your origin server in, say, Frankfurt. CDN caching reduces latency and takes load off your hosting. We cover CDNs in more depth in a separate guide on using a CDN with WordPress.
How the Caching Layers Work Together
Here's how a request flows through a well-cached WordPress site:
- The browser cache answers first. If the visitor already has your CSS and images, those aren't requested again.
- The CDN edge cache answers next. If it has a fresh copy of the page or asset, it serves it without contacting your server.
- The server page cache answers if the CDN doesn't. Nginx, Varnish, LiteSpeed, or a caching plugin returns saved HTML.
- If the page must be built, OPcache speeds up PHP, and the object cache answers many database questions from memory.
- Only what's left actually hits the database.
Each layer reduces the work for the layers behind it. You don't need every layer on day one, but page caching plus OPcache is the minimum for almost any site.
Cache Invalidation: Keeping Content Fresh
The hardest part of caching is knowing when to throw a copy away. If you update a post and visitors still see the old version, your cache isn't being cleared correctly.
Good caching tools purge automatically when:
- You publish, update, or delete a post or page.
- Someone leaves an approved comment.
- You change menus, widgets, or theme settings.
- You update plugins or themes.
Related pages usually need clearing too. When you publish a new post, your homepage, blog archive, category archives, and RSS feed all change. Most caching plugins handle this "smart purge" for you.
When something looks wrong, you can clear caches manually. Most plugins add a Clear cache or Purge all button to the admin toolbar. From the command line, you can flush the object cache with WP-CLI:
# Flush the object cache (including Redis or Memcached if connected)
wp cache flush
# Delete all transients
wp transient delete --all
If you use a CDN, remember to purge it too, either from the CDN dashboard or via its WordPress integration.
How to Set Up Caching on Your WordPress Site
Here's a practical order of operations:
-
Check what your host already provides: Many managed WordPress hosts include server-level page caching, object caching, and a CDN. Installing a second page caching plugin on top can cause conflicts, so read your host's documentation first.
-
Enable page caching: If your host doesn't cache pages, install one caching plugin. WP Super Cache is simple and free, W3 Total Cache is very configurable, WP Rocket is a popular premium option, and LiteSpeed Cache is the best choice if your server runs LiteSpeed.
-
Turn on browser caching: Use your caching plugin's option or add the server rules shown above.
-
Add a persistent object cache: If your host supports Redis or Memcached, enable it and install the matching drop-in, especially for WooCommerce or membership sites.
-
Add a CDN: Put static assets, and optionally HTML, on a CDN to serve visitors worldwide.
-
Test the result: Load your site in a private window and check the response headers. Many caches add headers like
x-cache: HIT,cf-cache-status: HIT, orx-litespeed-cache: hit. You can see them in your browser's developer tools under the Network tab.
You can also check headers from the command line:
curl -sI https://example.com/ | grep -i -E "cache|age|server"
Run it twice. The second request should show a cache hit.
Common Caching Problems and How to Fix Them
Changes don't appear after editing: Clear your page cache, CDN cache, and browser cache. If this happens often, check that your plugin's automatic purge settings are enabled.
Logged-in content shown to other visitors: This is serious and usually means a page cache is caching pages it shouldn't. Make sure logged-in users, carts, checkout, and account pages are excluded.
Forms or nonces failing: Nonces expire, typically within 12 to 24 hours. If cached pages include forms with nonces and your cache lifetime is longer, submissions can fail. Shorten the cache lifetime for those pages, exclude them, or use a form plugin that refreshes nonces dynamically.
Two caching plugins at once: Running two page caching plugins causes unpredictable behavior. Pick one and fully deactivate the other, including removing leftover rules from .htaccess and any advanced-cache.php file in wp-content.
Minification breaks the layout: Many caching plugins also minify and combine CSS and JavaScript. That isn't really caching, and it can break things. Turn those options off one at a time to find the culprit.
FAQ: WordPress Caching
Caching in WordPress is the process of storing ready-made copies of pages, database query results, or files so they can be served quickly on later requests instead of being generated from scratch each time.
WordPress has a built-in object cache and the Transients API, but the object cache only lasts for a single request by default. It doesn't include full page caching, so you need a plugin, your host, or a CDN for that.
Page caching usually has the biggest impact, because it lets your server skip PHP and database work entirely for most visitors. Persistent object caching matters most for logged-in users and dynamic sites like online stores.
Often not. Many managed WordPress hosts provide server-level page caching and may even block certain caching plugins. Check your host's documentation, and use a plugin only for features your host doesn't cover.
Page caching stores the complete HTML of a page. Object caching stores smaller pieces of data, such as database query results, which WordPress uses while building pages that can't be served from the page cache.
Use your caching plugin's Clear cache or Purge all button, clear your CDN cache from its dashboard, and run wp cache flush with WP-CLI for the object cache. Then do a hard refresh in your browser.
Caching itself rarely breaks a site, but misconfigured caching can show outdated content, cache personalized pages, or interfere with forms. Optimization features bundled with caching plugins, like minification, cause most layout problems.
Conclusion
Caching in WordPress is all about not doing the same work twice. Browser caching keeps files on your visitors' devices, page caching serves finished HTML without touching PHP, object caching and transients store expensive data in memory or the database, OPcache speeds up PHP itself, and a CDN brings everything closer to your audience. Together, these layers can turn a sluggish site into a fast one without changing your content at all.
Start with what your host provides, add a single page caching solution if you need one, and consider Redis or Memcached for dynamic sites. Then test that your cache is actually hitting, make sure it purges when you update content, and exclude personalized pages. Get those basics right, and caching will quietly make your WordPress site faster and more reliable every day.


