Versioning WordPress static assets keeps browsers and CDN edges from reusing an old stylesheet or script after a theme or plugin deployment. When the asset URL changes with the file change, the next request targets a new cache key instead of waiting for the previous object to expire everywhere.
The usual WordPress hook point is the version argument in wp_enqueue_style() or wp_enqueue_script(). That argument is appended to the asset URL as a query string, but the default behavior matters: if the argument is omitted or left as false, WordPress adds its own core version instead, which does not change when only a theme or plugin asset changes.
The safest version source depends on the deployment model. filemtime() is practical on a single node or during development, while a build hash or release string is more stable across multiple web heads. If the CDN cache policy ignores query strings, changing ?ver= will not create a new edge object, so versioned filenames or paths are the stronger fallback.
$ rg -n "wp_enqueue_style|wp_enqueue_script" wp-content/themes wp-content/plugins wp-content/themes/example/functions.php:18:wp_enqueue_style( wp-content/themes/example/functions.php:26:wp_enqueue_script(
Use the wp_enqueue_scripts hook for front-end assets, admin_enqueue_scripts for dashboard assets, and login_enqueue_scripts for the login screen.
wp_enqueue_style( 'site-style', get_stylesheet_directory_uri() . '/assets/css/site.css', array(), filemtime( get_stylesheet_directory() . '/assets/css/site.css' ) );
For a plugin asset, use the matching filesystem path helper such as plugin_dir_path( __FILE__ ) with the public URL from plugins_url().
When the asset lives in the parent theme, switch the path helpers from get_stylesheet_directory() to get_template_directory().
wp_enqueue_script( 'site-app', get_stylesheet_directory_uri() . '/assets/js/app.js', array(), 'build-a1b2c3d4', array( 'in_footer' => true ) );
Replace build-a1b2c3d4 with the real build hash or release string emitted by the deployment pipeline so every node serves the same asset URL.
When the CDN includes query strings in its cache key, a changed ?ver= value is enough. When the cache policy ignores query strings, rename the built file itself, such as app.a1b2c3d4.js or site.20260329.css, instead of relying on the query string alone.
If the HTML starts referencing the new asset URL before the new file is present on every node or origin, the CDN can cache a temporary 404 or stale response for the new path.
Use build-hash versioning instead of filemtime() when shared storage, parallel deploys, or container image rollouts can leave different nodes with different modification times for the same logical release.
$ curl -s https://www.example.com/ | rg '/wp-content/.+(site\\.css|app\\.js)\\?ver=' <link rel='stylesheet' id='site-style-css' href='https://www.example.com/wp-content/themes/example/assets/css/site.css?ver=1743210025' type='text/css' media='all' /> <script src='https://www.example.com/wp-content/themes/example/assets/js/app.js?ver=build-a1b2c3d4' id='site-app-js'></script>
Success is visible when the HTML contains the new version value and the corresponding asset request returns the expected 200 or 304.
Versioned asset URLs reduce the need for repeated full-site invalidations, but a targeted invalidation is still useful when the CDN is holding the old page markup or an already cached error response.