Like the other countless users who’ve downloaded the W3 Total Cache plugin, or manually set expires headers, I want my sites to be fast. Requests should be served from cache whenever possible. But what happens when you want to update a stylesheet in production? How can you tell your site to serve the latest version?

We’ve got a couple options on the table to accomplish this. I’ll run you through both below, with a css file as the example. Prior to the options, I’ll also provide a simple tutorial on how to setup a dynamic cache busting variable in PHP, which should update automatically for you when you make changes to your css file.

I’ll be scoping this tutorial to WordPress users using the wp_register_style function to call their stylesheets, but these strategies will work for busting cache on any site. Ok, let’s get to it!

Dynamic Cache Busting Variable

First, we’ll setup a variable that will update every time we make a change to our file. This variable will later go into our requests for our cacheable assets.

PHP

$cacheBusterCSS = date("Y m d", filemtime( get_stylesheet_directory() . '/library/css/style.css'));

Ok, so a few things are happening here. We’ll start on the inside and work our way outward. First, I’m calling the css file prepended with the get_stylesheet_directory function. This function is inherent to WordPress, and will ensure the correct absolute server path to our file, either locally or on our live site.

Next, we are wrapping the file call in the php filemtime function. This function returns the time when the content of the file was last changed.

Finally, we’ll pass that into a date function, which will give us back our variable in a nice clean format, ie. 20130410. This is the value we’ll pass to our files in order to bust cache. Since it updates every time we update the file, there is no manual work. Now, on to using this variable.

Query Strings

The first option for busting cache is appending a query string to the end of our requests. We’ll use the above variable as that query string.

PHP

// cache busting variables for statics
$cacheBusterCSS = date("Y m d", filemtime( get_stylesheet_directory() . '/library/css/style.css'));

// register main stylesheet
wp_register_style( 'main-stylesheet', get_stylesheet_directory_uri() . '/library/css/style.css', array(), $cacheBusterCSS, 'all' );

As you can see, I’m using the wp_register_style function to call my stylesheet in the above code. You can call yours however you’d like, and this should work. After setting up the source for my file, I’m then adding our cacheBusterCSS variable in as the fourth parameter, denoting a version. The version is appended to the stylesheet URL as a query string, such as ?ver=20130410. This query string will ensure the correct version of the file is sent to the client, regardless of cache.

File Naming

The second option is renaming the file altogether when you make a change, and using a rewrite rule to reroute the requests to the original file.

.htaccess

<IfModule mod_rewrite.c>
  RewriteCond %{REQUEST_FILENAME} !-f
  RewriteCond %{REQUEST_FILENAME} !-d
  RewriteRule ^(.+)\.(\d+)\.(js|css|png|jpg|gif)$ $1.$3 [L]
</IfModule>

This will route all requests to /path/filename.20130410.css to /path/filename.css, for example. It is scoped to the above file types, so change it as necessary.

PHP

// cache busting variables for statics
$cacheBusterCSS = date("Y m d", filemtime( get_stylesheet_directory() . '/library/css/style.css'));

// register main stylesheet
wp_register_style( 'main-stylesheet', get_stylesheet_directory_uri() . '/library/css/style.' . $cacheBusterCSS . '.css', array(), null, 'all' );

In our PHP, we will call the file in almost the same way as above, with a few small tweaks. Rather than passing our cacheBusterCSS variable as a query string parameter, we’ll concatenate it with the filename. Then we’ll pass null to the query string param. And there you have it! The above file will be style.20130410.css, which will route to style.css. The change in filename will bust our cache, sending the correct version to the client.

Which Is Better?

Ah yes, but what about a verdict? Well, if you’ve viewed source on this site, you can see that I’ve chosen the file renaming method. There are a few reasons for this; First, it’s the preferred method in HTML5 Boilerplate, which is about as close to a gold standard as you can get. Secondly, Steve Souders states that some popular proxies don’t cache resources with a query string.

So why include the option at all? Well, some of you may not have access to your .htaccess file for one reason or another, or you aren’t comfortable editing it (ignoring the obvious question of how you setup caching in the first place). It also seems to be the standard solution in WordPress, as the inherent functions support query strings.

Anywho, let me know what you think! Some of you may be using build scripts or other strategies for busting cache, and I’d love to hear them!