How to Leverage Browser Caching in WordPress

How to Leverage Browser Caching in WordPress to Optimize Page Load Time

Optimizing a website for speed is a never ending quest. There is always something you can tweak to shame milliseconds off each load. While that might not sound like a lot, each tweak ads up.

I’ve talked about caching before, but that was all server-side caching. That’s the low-hanging fruit because you can control it a lot more and it will make a bigger overall difference. 

Once you’ve plucked the low-hanging fruit though, there are still things you can do to speed things up. One of those things is taking advantage of browser caching. 

Differences Between Browser Caching And Server Caching

Previously we discussed server-side caching. That is, saving off the results of expensive operations so that we don’t execute them on every page load. API calls and complex database queries are good examples of things that should be cached server side. Our video on object caching can help you figure out this better:

On the contrary, browser caching has nothing to do with “expensive operations” and is all about reducing the actual number of bytes that are pulled across the wire each time someone loads a page from your website. 

What Is Browser Caching?

All modern browsers set aside a portion of your file system to temporarily store things. This is called its cache. Modern websites are made of a lot of different pieces of content:

  • HTML
  • Images
  • CSS
  • JavaScript
  • Other media

Some of these pieces of content are static, in that they never or rarely change. For example, your company’s logo probably won’t change often. Storing the graphic of your company’s logo in the browser’s cache means that’s one less thing that has to actually be fetched from your server for your image to paint.

How Browser Caching Works In WordPress

When a user types a URL into a browser, it starts a conversation between the browser and the server.

Browser: Hey, do you host this page?

Server: Yes, here’s the HTML

Browser: [Reads HTML and builds a list of the things it needs to request to display the page]

Browser: Ok, here’s the list of other things I need to display the page

Server: Here ya go…

Server: Here ya go…

Server: Here ya go…

The server keeps going until it has given the browser all the things it has requested. Sometimes these are small graphics, other times these are large JavaScript files or CSS files. Regardless of what they are, without browser caching, the browser has to ask for each and every one of these items, every time.

What if a user is visiting your shop and browsing? They may click 5,10,15 pages. Most of the pieces of these pages are the same thing over and over again. Your base CSS, your JavaScript, your company’s logo… never change between pages. But the browser has to ask for it each time and the server has to send it.

Browser caching lets the browser decide to temporarily store some of these pieces and reuse them. This shortens the conversation between the browser and the server. After the server hands the browser the HTML of the page, the browser builds its list of things it needs to display the page. With browser caching, it then looks at the list of things it already has and strikes them from the list before continuing the discussion with the server.

How browser caching works

Controlling The Browser Cache

The problem is that browsers aren’t that bright. Left to their own devices, they would simply cache everything and never request anything. While this would make the user experience very fast, eventually the browser would be showing the user old data. 

Can you imagine your browser storing the current score of your favorite sports-ball match? No matter how much time passed or how many times you hit refresh, the score would never change because the browser has cached the score already. 

So obviously we need some way to tell the browser what can and cannot be cached. Even for the things that can be cached, we want to tell the browser when it’s no longer any good so it knows to ask for a new copy. For that, we use “Headers”.

In the conversation between the browser and the server, there is data that is passed both ways on each request, these are called headers. Users never see headers but they can affect the content that the user sees.

Servers send different headers to the browser to help it figure out what it can cache and where. There are several different headers and values that the server and browser can exchange to control caching- For the most part, it boils down to these 2:

1. Cache-Control

The Cache-Control header is the first one looked at by the browser. It tells the browser what it can do with the entity it just received. The most important possible values are:

  • no-cache
    This tells the browser it’s ok to cache this resource but it has to check with the server to make sure it has the most recent version.
  • public
    This tells the browser – or an intermediary like a CDN – that it’s ok to cache this resource.
  • private
    This means that this is a cacheable resource but only by the browser. CDNs canc’e cache this resource. 
  • no-store
    This tells the browser that this resource should never be cached.

2. Expires

This header tells the browser when this resource should be considered “stale”. This means that after this date and time, the browser needs to request a new copy of the resource.

With these 2 headers, a browser can now make an intelligent decision about caching any given resource.

So really, the only thing we need to know now is how to set the headers that our server sends to a browser.

How To Leverage Browser Caching In WordPress?

As with everything in WordPress, there’s the hard way and the easy way to do it. The hard way is usually the way we used to do it before someone figured out the easy way. The hard way almost always involves editing a file manually and usually involves hiring a developer to help you. The easy way almost always involves installing and configuring a plugin. 

The Hard Way: Leveraging Browser Caching By Setting Caching Headers Manually

If you are dead-set on doing things the hard way, this involves modifying a file in the root of your website named “.htaccess”.  (The leading dot is important)

If you open this file in an editor, you can add “ExpiresByType” lines to define how long a specific type of resource should be cached.

For instance:

ExpiresByType text/css “access 1 month”

This tells the server to tell the browser that any given CSS resource can be cached in the browser’s cache for 1 month before requesting a new copy.

You need to make this decision for every type of resource that you serve and add a record into the file for it. This is a time-consuming process and you have to remember you did it this way in case you want to manually adjust the times.

Here is a common set of headings you can use in your .htaccess file.

<IfModule mod_expires.c>

  ExpiresActive On

  ExpiresByType image/jpg “access 1 year”

  ExpiresByType image/jpg “access 1 year”

  ExpiresByType image/gif “access 1 year”

  ExpiresByType image/png “access 1 year”

  ExpiresByType text/css “access 1 month”

  ExpiresByType application/pdf “access 1 month”

  ExpiresByType application/javascript “access 1 month”

  ExpiresByType application/x-javascript “access 1 month”

  ExpiresByType application/x-shockwave-flash “access 1 month”

  ExpiresByType image/x-icon “access 1 year”

  ExpiresDefault “access 2 days”


That covers most types of resources that your server will serve. 

The upside to the hard way is that it gives you absolute control over the caching on the browser. 

Personally, this is my preferred way to set caching headers. That having been said, I am a programmer and enjoy doing things the hard way. You may want to look at a plugin to leverage browser caching easily.

The Easy Way: Leveraging Browser Caching Using A WordPress Plugin

As with everything in WordPress, “there’s a plugin for that”. Leveraging the browser cache is no exception. Many of the most popular caching plugins have options that you can use to fine-tune the browser cache headers. By default, WordPress will add “Cache-Control” headers to all static resources (CSS, JS, etc) The plugins will add them to more than just that as well as give you more granular control.

If SiteGround is your hosting partner, you don’t need to worry about this. These headers are already configured for you. Nevertheless, If you are not yet hosting your WordPress site with SiteGround, you can use the SiteGround Optimizer plugin to insert the caching headers into your .htaccess file for you.

If you already have the SiteGround Optimizer plugin installed – and you should – Select the “Environment” menu option from the main menu or click on “Go To Environment” on the dashboard page.

Leverage Browser Caching with SiteGround Optimizer Plugin

There, you will find “Browser Caching” in the middle of the page. Click the slider to green and you are good to go. This option won’t be visible in the SiteGround Optimizer plugin installed on websites, hosted with us, because we manage this for our clients.

Leverage browser caching functionality in SiteGround Optimizer plugin

Cache Busting

Regardless of how you set your cache headers, sometimes you want to tell the browser “Hey, I know I said hold on to this resource for a month, but I’ve got a new copy and you need to ask for it.” This is called “Cache Busting”.

In WordPress, the way we bust caches is to append a version number to the name of the file.

For example:

<script src=”/js/jquery.js” />

Regardless of how many times we update jquery.js, the browser isn’t going to request a new copy until this one expires based on the rules we set. That is why most resources that are loaded in WordPress include a version number as part of the query string.

<script src=”/js/jquery.min.js?ver=3.6.0” />

The browser stores the complete file name jquery.min.js?ver=3.6.0 as the key for this resource. So if we change the ver= part, it thinks it’s a new resource and requests it regardless of the status of the caching headers.

<script src=”/js/jquery.min.js?ver=3.6.1” />

That’s how we bust caches and request fresh resources even if the ones we have haven’t expired.

Speed Results After Leveraging Browser Caching

So does all of this make any difference? A lot of that depends on your other optimizations already implemented. For one of my production sites, I had implemented all the SG Optimizer plugin recommendations. This took me to a Google Page Score of 87.

Google score of 87 without using SiteGround Optimizer

Then, I added the caching headers described above to my .htaccess file. This was the only change I made to the site. Now when I run SG Optimizer Speed Test, I get a score of 92!

Google Score of 92 after using SiteGround Optimizer to leverage browser caching in WordPress

So yes, five points on Google Page Speed score was worth the 2 minutes it took me to leverage browser caching. 

I hope your results are even better!

🚀 Get SiteGround Optimizer for FREE

–> Click here to learn more and download the plugin

Access email sent!

Sign Up For
More Awesome Content!

Subscribe to receive our monthly newsletters with the latest helpful content and offers from SiteGround.


Please check your email to confirm your subscription.

author avatar

Cal Evans

PHP Evangelist

One of the most admired people in the PHP community, who has dedicated more than 16 years to building the amazing PHP community and mentoring the next generation of developers. We are extremely honored that he is a very special friend of SiteGround too.

Comments ( 8 )

author avatar


Jul 10, 2022

On SiteGround, for static websites not using WordPress, what is the difference between this ExpiresByType approach versus using a kind of approach? Are both needed, or is only one approach sufficient?

author avatar

Gergana Zhecheva Siteground Team

Jul 11, 2022

Hey Kathy, unfortunately, it's a bit unclear what is the second approach you are referring to. The information in your .htaccess file specifies for how long each of these types of files will be cached, and you can control that to some extent via the ExpiresByType directives listed in the article.

author avatar


Jul 14, 2022

sorry. the "FilesMatch" got deleted somehow. Is just using FilesMatch enough? Or is the ExpiresbyType also needed? AND, for a static site, should all Cache Control headers be set to "private" along with the max-age then?

author avatar

Elena Chavdarova Siteground Team

Jul 18, 2022

Hello Kathy, Leverage Browser Caching rules can be applied via FilesMatch rules as well. Still there shouldn't be two .htaccess rules applied for the same headers. We recommend to replace those rules with the ones listed in this blog post. In case your website is a static one it is good to have the cache headers set to public, so the content can be fully cached. In case there no cache-control rules set on the .htaccess file of your website - the headers will be public by default, so there is no need of additional rules applied.

author avatar


Jul 12, 2022

Is there a reason I do not have this option on any of the websites I manage? All are hosted with you and all have the optimizer plugin installed... but when I go to the environment tab as the article suggests, I do not have the option to choose browser caching.

author avatar

Gergana Zhecheva Siteground Team

Jul 15, 2022

That is the expected behavior, as at SiteGround we manage this for our clients. The section Browser Caching would be visible for plugin users that are hosted with other web hosts. Hope that helps!

author avatar


Sep 09, 2022

I could not find Browser Caching, and Gzip compression in the Environment tab as shown in the image above.. is it an older version?

author avatar

Gergana Zhecheva Siteground Team

Sep 09, 2022

The options are visible in the menu only for websites hosted at other web hosts on which you have installed the plugin. For websites we host, we manage these two settings, and that is why you do not see them. We have added a clarification in the text, thank you for your question!


Start discussion

Related Posts