How to create and retrieve cache-busting filenames for static assets in WordPress
Admission: I’ve never had a workflow in place for developing WordPress websites where static assets can be set to expire in the far future without the worry of how to serve an updated version.
I would guess and cherry-pick assets with a high probability of remaining unchanged, telling browsers to assume they would never expire, while manually versioning “likely to change” files with a query string (and, yup, I’m aware of the ancient 2008 prophecy with regards to URLs using query strings).
In actuality, this hasn’t been as horrific as it sounds, largely due to the type of sites I tend to end up working on: highly-customised WordPress websites that are treated as set-and-forget by clients as soon as they’re launched. Regardless: so sorry.
But! I recently worked on a new site using Hugo, treating it as an opportunity to quash some bad practices. Of course, someone had already solved and typed up their sweet solution for cache-busting static assets for Hugo. This got me thinking about how to implement something similar in WordPress.
To keep things simple, let’s deal with a single asset: the WordPress theme’s stylesheet.
The WordPress way
Every WordPress theme expects a file named
style.css, and it’s one of the few files that cannot be omitted from a theme directory. This file performs two tasks:
- It serves as a known location within WordPress for the theme’s stylesheet.
- It contains a header which is used to provide useful details about the theme: name, author, version; and so on.
This means any theme directory serving an alternate file containing the theme’s style rules should still contain a
style.css file. As you’ll see in the PHP function below, the default
style.css will serve as a fallback in case of a missing or mis-matched hashed filename.
Creating a hashed filename
This part is really down to what you’re using for tooling: Grunt; gulp; webpack; that new one everyone is using that I’ll find out about in a few months’ time.
For example, the following webpack config generates a CSS file called
dist/css/, where [contenthash] is a unique string. A JSON hash map in
/dist will be used by the PHP function below to map the correct hashed filename to style.css.
Regardless of what is used, the following needs to be generated:
- A version of
style.csswith a content hash as part of the filename.
- A JSON object with the key as
style.cssand the value as the hashed filename.
Additionally, you’ll need new locations for the new files. In the following example I’ll use “data” and “dist”:
data/contains the JSON hash map.
dist/contains the hash-appended files.
Using the JSON hash map
PHP time! Here’s a function to place in functions.php that will perform the work of retrieving a hashed filename, if it exists.
How it works
- When the function is called a value of
style.cssis passed in.
- A value for
$hashis set if it doesn't exist already (as a static variable its value persists, so the check for a null value ensures the value is only set one time).
- The retrieved JSON hash map is converted to a PHP array; if nothing is retrieved an empty array is set.
array_key_exists()is used to check the existence of the function's passed in value—style.css—as an array key, and, if it exists, the value for this key is returned.
- Otherwise, the default
Serving the hashed filename
Calling the function occurs as part of the enqueuing process for style.css. get_path_css() hijacks the second parameter of wp_enqueue_style in order to dynamically determine the correct path.
If there's a mismatch in filenames or the file simply doesn’t exist, the default style.css will be enqueued.