Development

Cache Busting Scripts and Styles

All browsers implement a private, client-side browser cache. When a browser visits a page, it downloads the scripts and stylesheets (amongst other assets) into its cache. This caching is beneficial to performance, reducing network traffic and page load times. Other pages on a site may implement the same assets. So, it is faster to reuse those assets from cache than it is to download them again on subsequent page loads. However, this same caching mechanism can also be a hindrance, under certain circumstances. If, for example, you make changes to your custom WordPress theme’s scripts and stylesheets, browsers may not see those changes, if they have already cached those assets during a previous visit. One tried and true method for dealing with this is the cache busting query string. This has been a useful approach for instructing a browser to use a “new” version of an asset when that asset has been modified.

When a script or stylesheet’s source URL changes with a cache busting query string, the browser sees it as a new and unique URL. So customstyle.css?ver=1.0.1 is considered distinct from customstyle.css?ver=1.0.0. If the browser had already cached ?ver=1.0.0, and it encounters ?ver=1.0.1, it will download a fresh copy of customstyle.css?ver=1.0.1 and use that.

And of course, for a developer working on a custom theme, WordPress already provides a way to supply a cache busting query string when registering or enqueueing scripts and stylesheets.

The wp_register_script(), wp_register_style(), wp_enqueue_script(), and wp_enqueue_style() functions all accept a version string argument for their $ver parameter. The documentation for these functions state that the $ver parameter is a string specifying the script or style’s version number, “…which is added to the URL as a query string for cache busting purposes.

To leverage this cache busting mechanism, when we enqueue a stylesheet for example, we simply add a version number as the fourth argument to our wp_enqueue_style() call:

For the above example, our stylesheet will be injected into the document head markup as something like:

Now, when we make changes to our customstyle.css stylesheet in the future, we increment the version number in our call to wp_enqueue_style(). That will change the asset’s cache busting query string, prompting browsers to download the ‘1.0.1’ version of the stylesheet, even it if had the older ‘1.0.0’ version already cached.

This query string technique is solid, and has been used for many years, and not only in WordPress. But there is also a potential drawback. This requires that we manually maintain/update version numbers in a PHP file whenever we make changes to our CSS file. If we forget to increment the version number in PHP (hey, we’re only human), our visitors’ browsers will continue using the older version until the browser’s cache expires or is manually flushed.

But there is another technique we can leverage to help alleviate that potential for human error. PHP’s filemtime() function takes the full path to a file and returns the time that file was last modified as a UNIX timestamp. Knowing this, we could leverage the file’s modification timestamp as our version number. Make a change in the CSS file, save it, and our version string changes automagically, without manual curation in a PHP file.

Here is how we might update our earlier example to take advantage of that:

Now our stylesheet markup might look something like this:

And the next time we modify that CSS file, our cache busting version query string will automagically update, and visitors’ browsers will get the latest style changes.

When not to use the filemtime() technique? There is a small performance hit when you read from the filesystem. The magnitude of that hit depends on many factors, some of which might be beyond your control, such as disk read speed. Therefore, control what you can, limit the number of files that you use this technique with. For a few custom scripts and styles in a custom theme, this is an imperceptible performance hit. However, filemtime() is not a great solution to use with dozens or hundreds of assets in one request. Keep it reasonable, so both you and your visitors can benefit from this technique.

Comments

1 thought on “Cache Busting Scripts and Styles

  1. > “However, filemtime() is not a great solution to use with dozens or hundreds of assets in one request.”

    On any operating system that isn’t an antique, the value of the lookup will have been cached in RAM by the kernel. Nothing will actually be happening that involves the physical storage layer. Even hundreds of such lookups wouldn’t make a detectable difference. (Do sites on which there are hundreds of CSS files and scripts loading even exist?).

Have a comment?

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

accessibilityadminaggregationanchorarrow-rightattach-iconbackupsblogbookmarksbuddypresscachingcalendarcaret-downcartunifiedcouponcrediblecredit-cardcustommigrationdesigndevecomfriendsgallerygoodgroupsgrowthhostingideasinternationalizationiphoneloyaltymailmaphealthmessagingArtboard 1migrationsmultiple-sourcesmultisitenewsnotificationsperformancephonepluginprofilesresearcharrowscalablescrapingsecuresecureseosharearrowarrowsourcestreamsupporttwitchunifiedupdatesvaultwebsitewordpress