Opencart 3 uses quite aggressive caching for performance. If your site is also making use of cache-expired headers and a CDN like Cloudflare, this can make it almost impossible to push style changes live. To force a cache-refresh for stylesheet.css when it has been updated, we need to change the URL it is referenced by in the header.twig template. We can do this by appending a version number as a parameter:
<link href="catalog/view/theme/mytheme/stylesheet/stylesheet.css?v={{ css_version }}" rel="stylesheet">
Ideally we want to only change the version number when the file itself has been modified, so that we can make use of caching thereafter. Using a random number for example would prevent the file from being cached at all. A simple way to do this is to use the CSS file’s modification date as a unix timestamp using the filemtime function.
To make it multisite-compatible, we also need to make sure we’re checking the CSS file for the current theme, which we can retrieve with the help of $this->config->get(‘theme_default_directory’).
<?xml version="1.0" encoding="utf-8"?>
<modification>
<name><![CDATA[CSS version number]]></name>
<code>mp_css_version</code>
<version>20260327</version>
<author><![CDATA[Robin Hislop]]></author>
<!-- Add a CSS version based on date-modified as a cache-buster -->
<file path="catalog/controller/common/header.php">
<operation>
<search><![CDATA[return $this->load->view('common/header', $data);]]></search>
<add position="before"><![CDATA[
// Add the CSS date-modified as a cache-busting parameter
$theme_folder = $this->config->get('theme_default_directory') ?? 'default';
$stylesheet_path = DIR_APPLICATION . 'view/theme/' . $theme_folder . '/stylesheet/stylesheet.css';
$data['css_version'] = (file_exists($stylesheet_path)) ? filemtime($stylesheet_path) : time();
]]></add>
</operation>
</file>
</modification>
Remember to flush the modification cache and the theme cache to see your changes!