Issues with Cached CSS and JS files on WordPress?

Development
Ken Foubert
04/04/18

Missing updates to your stylesheet or JavaScript file on WordPress? Try this trick!

Did you make an update to your stylesheet or JavaScript file and it worked great on your WordPress development environment, but after deploying, your updates are missing? This common trick may help, which involves adding a version tag to your file, forcing both server and client-side caching to get the latest version of your file.

If you’re using the WordPress functions wp_enqueue_script and wp_enqueue_style (hint: you should be), you can take advantage of the 4th parameter to add a version number. I would suggest, if you’re adding the files to the theme, to use the file last modified date to set the version number, so that you don’t have to ever change the version number manually. If you’re managing a plugin, use the defined version number of your plugin with the enqueue functions.

Example

I have a header.php file that uses wp_enqueue_script and wp_enqueue_style for the custom theme and javascript. I updated the 4th parameter to use the last modified of the files to set the version number. Scroll horizontally to view the full code below:

/**
 * Load and set version for script and style files
 */
function my_enqueue_files() 
{
  // add site css.
  wp_enqueue_style(
    'site-css',
    get_stylesheet_directory_uri() . '/ css/site.css',
    array(), // this asset doesn't depend on any others
    filemtime(get_template_directory() . '/js/site.js') // use file modified date to set version
  );

  // add site javascript.
  wp_enqueue_script(
    'site-js',
    get_template_directory_uri() . '/js/site.js',
    array('jquery'), // this script depends on jQuery
    filemtime(get_template_directory() . '/js/site.js'), // uses file modified date again
    true // render this script in the footer so page loading isn't blocked
  );
} add_action( 'wp_enqueue_scripts', 'my_enqueue_files' ); 

You can view another example in this comment on the WordPress wp_enqueue_script page.

Final Results

Now, whenever you make changes to your stylesheet or javascript file, you don’t have to worry about the server or browser using an outdated version.

Using Grunt or Similar Task Automation Tool

If you’re utilizing Grunt or a similar task automation tool to process and minify your JS/CSS, there’s room to optimize this a bit. The following Grunt task can be used to write a new version number to a single file every time your JS/CSS is updated:

/**
 * Generate a new asset.version file for cache busting,
 * based off of Date.now()
 */
grunt.registerTask(
  'assets_version',
  'Generate a new assets.version file for cache busting',
  function() {
    var date = Date.now();
    grunt.file.write( 'assets.version', date );
  }
);

Using this technique, you can determine the version number to use when enqueuing your assets once and use that same value for all of the files you’re enqueuing instead of having to touch each file individually.

To do that, you need to tweak how you get the version number from the filesystem in your PHP. Where before the code just called filemtime on the file path, you can instead call a helper function to grab the version number and save the value for later, so that we only need to read from the filesystem once!

/**
 * Get the assets version number from the filesystem
 *
 * @return string the version number as of the last asset compilation by Grunt
 */
function get_version_number()
{
  static $assetsVersion;
  if (empty($assetsVersion)) {
    $assetsVersion = file_get_contents(get_template_directory() . '/assets.version');
  }
  return $assetsVersion;
}

/**
 * Load and set version for script and style files
 */
function my_enqueue_files() 
{
  // add site css.
  wp_enqueue_style(
    'site-css',
    get_stylesheet_directory_uri() . '/ css/site.css',
    array(), // this asset doesn't depend on any others
    get_version_number()
  );

  // add site javascript.
  wp_enqueue_script(
    'site-js',
    get_template_directory_uri() . '/js/site.js',
    array('jquery'), // this script depends on jQuery
    get_version_number(),
    true // render this script in the footer so page loading isn't blocked
  );
}
add_action( 'wp_enqueue_scripts', 'my_enqueue_files' );

The static $assetsVersion statement tells PHP to save that value for later, so that it only has to read from the filesystem the first time get_version_number() is called.