When it comes to site and server performance, I don’t know if there is anything more convoluted than the topic of caching. When we ask folks to clear their caches, many are confused, and rightly so. It isn’t just you! The main issue is that there are so many types of caching, so we’re first going to look at some practical, real-world, examples of caching.
Caching Food
Yes, I said “food”, as this helps us to understand one of the key benefits of caching. Imagine a world where, every time you are hungry, you have to go to the store to get the food you want to eat. Perhaps even more accurately, it would be like going to a restaurant every time to eat. Not just meals, but snacks, dessert, everything! Yes, some people live like that, but it isn’t efficient, and costs them more than they realize.
What do we do to avoid this scenario? We go to a grocery store, and we stock up. Some folks get enough for a day or two, some go once a week, and others will stock up with an entire month’s worth of groceries at a time. Besides the money we save by making our own meals, we save on something else that is the most relevant to this discussion: travel time.
And Wood
“Travel time” isn’t the only benefit that caching brings us, and that’s where our second real world example comes in: using a wood-burning stove for heat. For some, this isn’t an exercise in imagination, but real world, every day. For many of us though, this might feel like stepping back in time. Either way, if you’re going to use a wood stove for heat, you need fuel. And if you live in the frigid north like I do, and winter is closer to 4-5 months of the year, you need a lot of fuel. I know, I know, our Canadian friends have it even worse!
At any rate, to get that fuel, we chop wood when we don’t need it, creating a large “cache” of wood that is ready when we do need it. We do extra work up front, so that we don’t have to go out in below-zero weather to chop wood for the fire. You might say, “Hey, you still have to chop the same amount of wood!” And you’d be right, but doing it ahead of time still saves you time and effort–not to mention, you burn more calories in the cold.
Connecting the Dots
Now, these analogies aren’t perfect, but they show us the main benefits of caching, which is to save on “travel time”, and to save on “effort”. The various caching strategies all work towards these ends: page caching, asset caching, PHP caching, object caching, and browser caching. Yeah, there’s a lot of them, and multiple ways to do each one! As we go through this list, we’ll discuss how they work, what they accomplish, and how each cache can be purged.
Caching Pages
Now, what we really mean when we say “page caching”, is that we are caching the HTML of the page. This is the code of your page that is generated by WordPress and PHP. Generating that HTML code takes time and effort, especially since WordPress (and your plugins, and your theme) has to get information from the database in order to know what is supposed to be displayed on any given page. So, by storing, or caching, the HTML that is the result of all that work, we save on the “effort” side of things, which also saves us time–sometimes a LOT of time!

Server-based
There are several ways to cache that HTML for each page, and generally the most performant is server-based page caching. Hosts like WP Engine, Kinsta, and SpinupWP have this built in, though it can be customized and turned off if needed. Most will have some default exclusions, to make sure sites with shopping carts or other dynamic functionality don’t serve stale/incorrect page content. WP Engine also lets you add your own exclusions to the page cache, though their support team can help you with that, just like Kinsta does.
With server-based caching, there is usually a plugin installed that allows you to purge the cache. Some are “must use” (MU) plugins that you don’t see in your plugin listing, but they still have either an admin-bar menu, or a menu entry in the back-end/wp-admin to purge the cache.
At this level, you may be purging all of the caches, not just page caching. If in doubt, you can check with your host to find out what all is being purged–or how to do it, if it isn’t obvious. For example, a WP Engine purge does everything, but SpinupWP has options to purge Page and Object caches separately. Besides a manual cache purge, most hosts will have automatic cache purging. For instance, when you update a page, the MU plugin will hook in and purge the cache–either the whole cache, or just that page, depending on the site configuration.
LiteSpeed Cache is kind of an odd duck, in that it is a normal plugin that you can install manually. However, it provides an interface to the server-based LSCache for page caching, and many web hosts that use LiteSpeed will have it installed for you automatically. So long as you’re using their built-in page caching, make sure you don’t remove the plugin.
Besides LSCache on LiteSpeed servers, some hosts may use Varnish for page caching, while others use Nginx for page caching. All of these store the page HTML to the disk/storage on your server, but the main benefit over plugin-based solutions is that running/talking to PHP is completely eliminated. On my test sites, LSCache comes in at about 50-60ms, where a plugin cache responds in 120-130ms. Speaking of plugin-based caching…
Plugin-based
Caching plugins operate similarly, in that they take the HTML generated by PHP and store it to disk. Again, this saves the time and effort of building the HTML, and querying the database. Unfortunately, plugin-based caches generally still have to run some PHP code. Even though the code involved is very minimal, it does take more time (double or more in our example above) than just grabbing a file from disk. Fortunately, some plugins will install server-based rules using .htaccess that eliminate talking to the PHP engine, and put them on par with server-based caching. WP Rocket is one of these, and our own SWIS Performance will be soon!

Just like server-based caches, most cache plugins will automatically purge the cache when you update something on your website. They will also usually come with built-in exclusions for dynamic sites, ignoring POST requests for shopping carts, query strings, and cookies that would indicate a user is logged in or has dynamic (user-specific) content displayed.
There are also some limitations to server-based caching, depending on how your host has it configured, so there are times it may make sense to run both a plugin-based cache, for longer-term storage, and server-based caching for short-term storage (10 minutes to an hour). We’ll get to the reasons for that when we discuss Browser Caching.
Edge-based
Ummm, what’s an edge, and what does it have to do with caching? This sort of caching builds on top of either of the two we already mentioned. It uses a CDN like Cloudflare to cache your page HTML at the “edge”. That is, on a CDN server that is nearest to your visitor, and this focuses on the travel time aspect we mentioned earlier. Instead of a visitor from Singapore getting an HTML/page response from New York City, that may take 300ms (or more), they get it directly from a server in Singapore.
This can be great for sites with a global audience, but it can also be tricky to handle e-commerce and other dynamic sites. WP Engine and Kinsta both have this available via their integration with Cloudflare, just watch out for issues. We ran into trouble with our login page when we tried it a few months ago, and for that reason we haven’t re-attempted it since. Edge-based caching is relatively new, so as hosts iron out the glitches, I’m sure it will improve, and we’ll try it again in the future.
CDN Caching
Since we’re talking about CDNs, let’s dig into how they cache things. First of all, a CDN (Content Distribution Network) can cache a lot more than pages, and usually that is the focus. That is, the goal is to cache your CSS, JS, fonts, and anything else needed to display your site, and store it at the edge nearest each visitor. Again, this saves on “travel time” so we aren’t going back to the store every time we want a cookie, or banana, or whatever. It can also speed up that delivery if your web server is a bit slow. And even if your server isn’t slow, a CDN frees up resources, so your server can focus on delivering pages faster.

Unlike a page cache, a CDN follows much simpler logic to know whether it should cache something. It looks mostly at the Cache-Control and Expires headers, and if those are set to allow caching, the file gets cached. How long? Again, that depends on those two headers, but you can often hard-code the expiration to be longer. Ideally, you want to set the longest cache duration possible, and you don’t want to purge the cache, ever.
Wait, what? Never purge the cache! Is that even possible?? Imagine you get your groceries home, and you’re eating a banana. All of a sudden, you decide you’d rather have an orange instead. Do you throw away all your groceries and buy the same stuff, but with oranges instead of bananas? That would be crazy, right? Right?? When we purge the CDN cache, it’s throwing away all the images, JS, CSS on all the servers, everywhere. Surely there’s got to be a better way?
There is, and it is called a query string. Besides the expiration bits, CDN servers can “vary” the cache based on certain “keys”, and the query string is one of those. In case you’re still scratching your head, consider a URL like https://e8ji9xm9vip.exactdn.com/wp-includes/css/dist/block-library/style.min.css?m=821
See that part at the end, after the question mark: “m=821”? That’s the query string, and if you have your CDN setup correctly, all you have to do is change the version when you change that file, and the CDN will think it is a brand new file. When it gets a request for https://e8ji9xm9vip.exactdn.com/wp-includes/css/dist/block-library/style.min.css?m=822, the CDN will ignore the m=821 version that it already has stored, and grab a fresh copy for your visitors. We have more detail on that in our docs, but just remember, throwing away all your groceries is silly!
PHP Caching
For this one, just turn on your opcache and don’t look back! Okay, okay, we’ll dig a little deeper than that… Now, PHP is a strange language, or at least much different than traditional programming languages. When you run your browser, or your favorite game, or MS Excel, or just about any program on your computer, you’re executing a “binary” that was compiled from code. That is, a compiler took the code written by the programmer(s), and turned it into something the computer could understand with 1′ and 0’s.
Guess what? Your web server doesn’t know how to speak PHP! So, when we load a WordPress page with PHP, the PHP engine/module has to compile the PHP into machine readable code. Compiling code takes time and effort, but… ooh! What if we could store that machine readable code for future use? Yes, that is exactly what the opcache module in PHP does!

On hosts like WP Engine, SpinupWP and Kinsta, this is on by default, and you can’t disable it. You rarely see issues with opcaching anymore, as the cache updates anytime your PHP code changes. Updated a plugin, your theme, or even WP core? Automatically purged! Otherwise, the most common way to purge the opcache is to reload the PHP or web server process. Something like so:
service php-fpm reload
or
service httpd reload
If you’re on a host with cPanel, check to be sure opcache is enabled when you change/upgrade PHP. By the way, if you’re not using PHP 8+ yet, it comes with improvements to the opcache module, so you should really get that upgraded soon.

Object Caching
Maybe I’m crazy, but this is the dumbest name for a cache, and the software to do it isn’t any better. Quick, what do you store in an object cache? Sure, objects… that’s so helpful, glad we had this discussion! Alright, let’s just call it what it really is, Database Caching. Yes, I know it can probably be used for other stuff, but when it comes to WordPress, we’re interested in Database Caching. And maybe that’s still Greek to you (sorry Greeks!), so let’s explain what problem this solves first.
As we mentioned earlier, when you load a page on your site, WordPress has to get all the information for displaying that page. This information is stored in a database, and includes all the options/settings on your site, which influence how different plugins (and your theme) will operate. Naturally, WordPress also has to retrieve the actual content of the page, or possibly multiple pages/posts, depending on what all will be displayed on a given page.
As you can imagine, this takes time, because that information has to travel from disk (long-term stable storage) to memory/RAM (short-term volatile storage). Then, it has to be handed to the CPU that processes all this information and the PHP code and gives you the HTML for the page. Now, not only is long-term storage slower than short-term storage, but it is further away from the CPU. Maybe that doesn’t seem like it would make a difference, but it does. There’s a reason the memory in your computer, and on your web server, is located as close as possible to the CPU.

When we implement Object/Database Caching then, we shorten our travel time, and we take the information from the database that was in slow storage and put it somewhere closer with fast storage. It reminds me of when my Grandma would make all sorts of canned goods: pickles, beets, soup, and more. She stored them in the basement where there was more space available, and it was cooler too. But when we’re ready to eat, we don’t leave the pickles downstairs, and keep running up and down every time someone wants a pickle. Rather, we put our pickles in a dish on the table where everyone can readily access them, and no one goes hungry!
Bad Gateways
Object caching has a couple implementations, Memcached and Redis. There are probably others, but these are the most common. Memcached is great because it is built right into PHP. Unfortunately, sometimes memcached doesn’t have a lot of memory to store data, so on sites with more dynamic content, or more traffic, Redis is a better solution.
You might also run into issues with 502 (Bad Gateway) errors. This is a weird error to receive, but it’s also a weird problem. On each page load, the first time any option from the wp_options table is queried, WordPress requests ALL of the autoloaded options from the database. After all, fetching all that data once is way faster than running 50, or 100, or 500 queries for each individual option. Unfortunately, some plugins will store data in autoloaded options that doesn’t belong there, and this can make that quick query into a sluggish nightmare. Worse, if the total data in the autoloaded options is larger than the available memory for memcached, the server will just refuse to respond.

So if you see a 502 error after enabling object caching, don’t panic! Just turn it back off, and then go find out what got stored in wp_options that doesn’t belong there. You might need to enlist the help of your web host or a developer, but this should get you started.
Browser Caching
Whew, this is the last one, we’re almost done! This is an important one though, as it speeds things up for folks who visit more than one of your pages. Or at least it should, if you aren’t using certain plugins and options that defeat browser caching… So, remember the Expiration and Cache-Control headers we mentioned earlier?

Before we get into the weeds, browser caching is when the visitor’s browser stores the assets from your site (JS, CSS, ,etc.), and then re-uses them later. Just like if you buy a dozen eggs, and only cook a few of them. There’s no need to go back to the store until you run out of eggs, or they expire. Except these are digital eggs and don’t run out–but they do expire. This can make repeat visits, or visits to multiple pages, really really fast. All that has to be loaded is the HTML for the page, and boom, done!
However, this has to be setup by your web host, and isn’t always setup optimally. Often, web hosts are far more conservative, because they don’t want to answer support tickets about browser caching causing you problems. Perhaps you’ve seen a recommendation to “Serve static assets with an efficient cache policy” or to “Leverage Browser Caching”. These are telling you you should have better Cache-Control headers.
Ideally then, you want to instruct the browser, via that Cache-Control header, to store those files for up to a year (31536000 seconds). If you’re using LiteSpeed or Apache, plugins like our SWIS Performance or WP Rocket will automatically setup improved caching rules for you. For anything else, check with your web host, or check out this guide for Nginx caching headers.
Look, you might be tempted to do only 2-3 months. But that’s already a long time for a visitor’s browser to have the wrong file, so don’t go half-way on this one. This is another area where query strings can be a huge help. If you change a query string, the browser always sees that as a new resource and will ignore the old one in the cache.
And if you’ve ever been tempted to replace an image on your WordPress site, so that you don’t have to update URLs, stop it! None of your repeat visitors are going to see the new image until the browser cache expires (months). So do yourself, and your visitors, a favor: upload a new image, with a new filename, and then update your URLs.
Browser Page Caching
Woah, did your browser cache and page cache just have a baby!? No, but your browser can cache pages too, surprise! I was helping someone a while back with an issue where they would update their site in Chrome, and then test it in Firefox to see what their visitors would see. To her utter frustration, nothing would change, sometimes for days it would be like that. Turns out, her web host’s caching setup/plugin was using a 1 week cache expiration for pages. Since she always used Firefox for testing, it already had stored a copy of many of her pages in the cache.
Similarly, with WP Engine’s caching setup, it also relies on the Cache-Control headers, which are exactly what the browser uses to see if it should re-use a page, or load it fresh from the server. So, perhaps you might set the WP Engine cache to something reasonable, like 1 day, or maybe even 1 week. Then, someone visits your site on Tuesday, and sees that you have an upcoming product launch on Thursday. So they check back on Thursday, and nothing has changed. Yikes! Your hosting provider may handle it differently, but just keep an eye out for that if you try to set your server cache to have a nice long cache time.
I prefer not to have browsers caching our pages. So if you’re like me, and your hosting provider does set the Cache-Control header to enable browser caching of pages, you can set the server cache to a short duration, like 10 minutes or an hour. Then setup a cache plugin like SWIS Performance to cache pages for 24 hours or more, since cache plugins don’t usually mess with the Cache-Control header for pages.
Wrapping it Up
In order to have snappy page loads, it’s best to have all these cache mechanisms in place. Understanding how they all work, and how they work together is also vital when you’re struggling to figure out why something won’t update. So take the time to find out what sort of caching your site/host has, and how you can purge those cache(s). Here’s a quick refresher/summary:
Page Caching:
- stores HTML of pages for re-use, saving time.
- can be purged via admin bar, sometimes via admin menu, and via plugin settings if using a caching plugin (or LiteSpeed).
CDN Caching:
- stores images, JS, CSS, fonts, and sometimes pages, so they are closer to your visitors, saves time.
- can be purged via CDN control panel, but that should be a last resort. Change filenames and query strings instead.
PHP Caching:
- stores compiled versions of PHP code (opcache), saves effort and as a result also time.
- should not need to be purged.
Object Caching:
- stores information retrieved from the database, saves time, and a little bit of effort too.
- can be purged via admin bar, admin menu, or sometimes via cache plugin. Sometimes separately, other times with a global purge.
Browser Caching:
- stores downloaded resources (images, JS, CSS, etc.), and sometimes pages, in your browser, so they can be re-used until they expire.
- can be purged in browser settings. But, since you can’t purge all your visitors’ browsers, make sure to change filenames and/or update query strings.
Fortunately, once you have things setup properly, page caching and object caching are about the only ones you should have to purge, and even that ought to be infrequent. Happy optimizing, and caching, and… wood-cutting, if you’re into that sort of thing! I like pickles though, Mmm mmm…


