Cache-busting enqueued scripts and styles in WordPress

Have you ever made a change to a CSS or JavaScript file on a client’s website, but your client reports they can’t see the changes?

You’ve told them to “hard refresh,” and it didn’t help? You’ve clicked the “Delete Cache” button in the WordPress admin, with no effect?

You’ve flipped your table in rage, and vented to your colleagues about how technically-stupid your client was for not seeing the same things as you did?

I have some good news and some bad news.

The bad news is, it’s kinda your fault this is happening, and your anger is misguided. The good news is, a problem like this is totally within your control to resolve.

I’m talking about cache-busting, and it’s a lot less intimidating than it sounds.

Once you grasp and apply the concept to your own projects, the days of telling your clients to “hard refresh” will be over.

Server-side vs. client-side caching

There are two “high-level” types of caching: server-side and client-side.

With server-side caching in place, a website visitor can refresh a page all day long, but may not see anything different until the website administrator clicks the “Delete Cache” button on the backend, even if HTML markup has been changed in the meantime.

Client-side caching happens on the website visitor’s device. In an attempt to avoid wasting bandwidth, browsers may decline to re-download assets with the same file name.

When we talk of cache-busting, we’re talking about client-side caching. Here’s a step-by-step breakdown of what exactly happens:

  1. Website visitor visits page, browser downloads CSS and JS files.
  2. Website administrator updates CSS and JS files, but nothing else.
  3. Website visitor visits same page, browser sees CSS and JS files of the same exact name, and incorrectly assumes they have not changed.
  4. Website visitor cannot see the effects of whatever CSS and JS the website administrator updated in point #2.

What’s one surefire way we could ensure a file with the “same exact name” isn’t downloaded? You could append a query string to the URL.

Append query strings to your static asset URLs

Here are some examples of query strings appended to the base stylesheet URL of: https://example.com/wp-content/themes/themetry/style.css

  • https://example.com/wp-content/themes/themetry/style.css?lolrandomletters
  • https://example.com/wp-content/themes/themetry/style.css?ver=1.0.1

All you have to do is put a question mark at the end of the URL, and literally anything you want after that. Just as long as the full URL (including query string) hasn’t been used before, the browser will download it again.

In WordPress

Hopefully, you’re using WordPress enqueue functions to load your scripts and styles. Both the wp_enqueue_script and wp_enqueue_style functions have parameters for version number.

For example, the following style enqueue function:

wp_enqueue_style( 'markov-style', get_stylesheet_uri(), array(), '20170506', 'all' );

Will produce this:

<link rel='stylesheet' id='markov-style-css'  href='https://themetry.com/wp-content/themes/markov/style.css?ver=20170506' type='text/css' media='all' />

And the following script enqueue function:

wp_enqueue_script( 'markov-navigation', get_template_directory_uri() . '/js/navigation.js', array(), '20151215', true );

Will produce this:

<script type='text/javascript' src='https://themetry.com/wp-content/themes/markov/js/navigation.js?ver=20151215'></script>

To add a touch of automation, you could replace a static value like ‘20151215’ with filemtime() (do not wrap it in quotes, it’s a PHP function) which will use a timestamp based on when the file was last modified.

This is probably best used on a development or staging server, especially if you don’t have any other page caching on your production site.

Other methods of cache busting

There are other methods of cache-busting, but in WordPress, the above outlined method is probably your best bet. CSS Tricks talks about some other ways that you might want to check out.

Leave a Reply

Your email address will not be published. Required fields are marked *