Suppose that we changed a lot of functionality for the module (templates, layouts, CSS) and we are going to move these changes to the production site, but a lot of customers have cached CSS in their browsers. So here is a question. How to force flush client's CSS cache and avoid file renaming (styles.css -> styles-v2.css). There is one logical way but it doesn't work in Magento, because it checks file existing (by the way this method works for JS files), see below:
<action method="addCss">
<stylesheet>css/styles.css?1</stylesheet>
</action>
Any ideas?
15 Answers 15
One way of dealing with this is enabling merging of CSS. Then you could just clear the cache and a new merged file would be created with a new file name.
System -> Configuration -> Developer -> CSS settings -> Merge CSS FilesAs far as I know, the hash code of the merged CSS file stays the same even if the underlying files changed - only if new files are added to the set of merged files, the hash changes. -- @Alex
Another way of dealing with this is instead of using the layout.xml,
just put them in your
page/html/head.phtml
Or create a block that contains a <style> tag with version number and put it in the XML in your head so you can have it load on only specific pages and still sticking to using the XML layouts.
-
11As far as I know, the hash code of the merged CSS file stays the same even if the underlying files changed - only if new files are added to the set of merged files, the hash changes.Alex– Alex2013年01月23日 08:27:58 +00:00Commented Jan 23, 2013 at 8:27
-
@Alex didn't know that, makes sense.Rick Kuipers– Rick Kuipers2013年01月23日 08:28:30 +00:00Commented Jan 23, 2013 at 8:28
-
4I haven't looked at this recently, but in the past the compilation of CSS / JS seems to actually add extra 'weight' to your site if you load different CSS / JS on different pages. It created a different compiled version per unique set of scripts. This means larger files that get compiled in are essentially being downloaded multiple times.Peter O'Callaghan– Peter O'Callaghan2013年01月23日 09:02:59 +00:00Commented Jan 23, 2013 at 9:02
-
@cags - Yep, basically, under these conditions, minifying and allowing all CSS/JS files to download once is the only speed enhancement that works.Fiasco Labs– Fiasco Labs2013年06月15日 19:45:05 +00:00Commented Jun 15, 2013 at 19:45
-
This can sometimes change CSS behavior, at least for me in Magento 1.9.2.1Goose– Goose2016年04月07日 19:48:29 +00:00Commented Apr 7, 2016 at 19:48
You can use the OpenSource Module Aoe_JsCssTstamp which adds timestamp information to the merged CSS files. Timestamps for plain (un-merged) CSS files are not yet supported however but this would be easy to implement.
There is a free extension on github 'Magento Cachebuster' that does exactly this. It re
https://github.com/gknoppe-guidance/magento-cachebuster
The module provides cachebusting by automatically altering the URI created by Magento for>static files by adding the timestamp of the file to the filename:
Before: http://www.example.com/js/varien/js.js After: http://www.example.com/js/varien/js.1324429472.js
-
2This module parses the HTML for each response to add the timestamps, which could potentially hurt performance. github.com/fbrnc/Aoe_JsCssTstamp does the same in a more performant way, but it needs to rewrite the design package model to accomplish it, while Cachebuster only uses an observer.Fabian Schmengler– Fabian Schmengler2015年05月21日 07:39:57 +00:00Commented May 21, 2015 at 7:39
I use my own extension Speedster Advanced for this. But the basic principle is that the name of the merged css and js files includes the timestamp of the last modified file - see Mage_Core_Model_Design_Package::getMergedCssUrl(). Any time you edit any of the css files a new file name is created causing browsers to request the new file instead of reusing the cached version. Since your head block might be cached a Magento cache refresh is needed.
-
Fooman Speedster gets my up vote great extensionBobadevv– Bobadevv2016年04月07日 21:16:43 +00:00Commented Apr 7, 2016 at 21:16
I also have implemented a cache buster for css files. Best way I guess is to extend Mage_Page_Block_Html_Head and over ride the function below and update $skinItems array with your desired changes.
protected function &_prepareStaticAndSkinElements($format, array $staticItems, array $skinItems, $mergeCallback = null)
{
$designPackage = Mage::getDesign();
//$skinItems: contains all css
foreach ($skinItems as $params => $rows) {
foreach ($rows as $key=>$name) {
$file = $designPackage->getFilename($name, array('_type' => 'skin'));
$skinItems[$params][$key] = $name . "?fmt=" . filemtime($file);
}
}
return parent::_prepareStaticAndSkinElements($format, $staticItems, $skinItems, $mergeCallback);
}
Got the inspiration from here. Source
-
1This won't work, the skin files will always fall back to base/default because the filename won't be found with the appended query string.BlueC– BlueC2016年09月21日 13:09:15 +00:00Commented Sep 21, 2016 at 13:09
-
your comments "The filename won't be found with the appended query string" thats what we want and thats what will bust the cache and force the cache server to fetch a fresh copy.Ahad Ali– Ahad Ali2016年09月22日 23:30:34 +00:00Commented Sep 22, 2016 at 23:30
-
1No, that isn't how it works at all. You are changing the values of the elements in the $skinItems array and then passing those back to the parent _prepareStaticAndSkinElements() method. This parent method will call Mage::getDesign()->getSkinUrl() on each modified item which will then always fallback to base/default because it can't locate the files with the appended ?fmt=xxx on the filesystem.BlueC– BlueC2016年09月23日 07:54:05 +00:00Commented Sep 23, 2016 at 7:54
-
Not sure about his implementation, but the inspiration sourced at the bottom definitely works exactly as you'd hope, github.com/mklooss/Loewenstark_HeadGoose– Goose2017年08月25日 17:52:44 +00:00Commented Aug 25, 2017 at 17:52
There is a simple but cumbersome workaround that doesn't require any plugins and just uses built in Magento capabilities - useful if you just have to quickly do it on an existing site without wanting to risk installing any more code.
The idea is that you can use the merged CSS system to generate a cache busting file name.
As the merged CSS file name is a hash of all the files that are merged together you simply add an extra blank css file into the theme with a date stamp for a name.
So:
- Turn on Merge CSS files in Configuration> Advanced> Developer
- In your theme layouts find where you add CSS files to the head (typically page.xml) and add an extra stylesheet file, call it anything you want as long as the name is unique
eg
<action method="addCss"><stylesheet>css/cachebust_091014.css</stylesheet></action> - In your skin CSS folder create a new css file with that name, for the file contents I just put a comment saying what the file is for
Now push that live and flush the magento cache, the merged css file will now have a different name and your caches will be busted!
It's cumbersome as each time you want to bust the cache you need to change that file name, but it requires nothing other than built in Magento capabilities so it's handy if you find yourself stuck and need a quick fix!
=> Instead of using this code:
<action method="addCss">
<stylesheet>css/styles.css?1</stylesheet>
</action>
=> Try to use this code :
<reference name="head">
<block type="core/text" name="foocss">
<action method="setText">
<css><![CDATA[<link rel="stylesheet" type="text/css" href="foo.css?1" media="all" />]]></css>
</action>
</block>
</reference>
But it's not very nice...
-
-
This is an excellent idea for a short term check.Jay El-Kaake– Jay El-Kaake2015年05月07日 15:31:51 +00:00Commented May 7, 2015 at 15:31
I found a module that will append a query string to the end of all CSS and JS in xml layouts. The query string is configurable from the admin.
https://github.com/mklooss/Loewenstark_Head
The basic idea is to override _prepareStaticAndSkinElements to include a query string, as done in the module, shown below.
protected function &_prepareStaticAndSkinElements($format, array $staticItems, array $skinItems, $mergeCallback = null)
{
$version = Mage::getStoreConfig("design/head/meta_version_tag");
$format = sprintf($format, "%s?v{$version}", "%s");
return parent::_prepareStaticAndSkinElements($format, $staticItems, $skinItems, $mergeCallback);
}
If I understand the proposed solution in your question, you can do that with a slight mod to a core file (don't actually edit the core file):
Mage/Page/Block/Html/Head.php
Add something like ?v=1 to line 198 so all css files have this appended:
$html .= $this->_prepareStaticAndSkinElements('<link rel="stylesheet" type="text/css" href="%s?v=1"%s />' . "\n",
I think Fooman Speedster Advanced (http://www.magentocommerce.com/magento-connect/fooman-speedsteradvanced-4030.html) could be a solution:
"Fully automated once installed, with automatic versioning when Javascript/CSS files are updated"
I have built a free module for this:
http://www.magentocommerce.com/magento-connect/frontend-flush-2048.html
Please let me know if it does not work as expected but I've built it so that the combined js and css files will have a different hash if the content of one of the concatenated files has changed. By default Magento only changes the hash of the combined file if the filename of one of the included files has changed.
UPDATE
I also made a free and simple minify module for the ones of you who believe in it.
http://www.magentocommerce.com/magento-connect/minify-7771.html
-
This module is not working...SIBHI S– SIBHI S2015年03月20日 09:12:41 +00:00Commented Mar 20, 2015 at 9:12
There's a really nice module created by Fabrizio Branca that does exactly the thing that you're interested in. It's called AOE_JsCSSTStamp . What it does? It adds a time stamp to both CSS and JS resources. When you flush CSS/JS cache then the timestamps are recreated.
The browser will see different filename - that's why it will redownload the resources again and be served with the freshest one instead of cached in the browser.
Just edit the method getCssJsHtml in Mage_Page_Block_Html_Head, add a string like this for a few days after css edit and that's all... it simply works
// static and skin css
$html .= $this->_prepareStaticAndSkinElements('<link rel="stylesheet" type="text/css" href="%s?foo=WHAT_YOU_WANT_HERE"%s />' . "\n",
empty($items['js_css']) ? [] : $items['js_css'],
empty($items['skin_css']) ? [] : $items['skin_css'],
$shouldMergeCss ? [Mage::getDesign(), 'getMergedCssUrl'] : null
);
Few years later and not finding any useful extension that won't merge files and is simple, I created my own. The main idea is that after flushing cache, it will update the Timestamp. So in other words - when you change some css/js, just flush cache and Timestamp will be updated.
Source code is here -> https://github.com/archonkulis/ANSolutions_CssJsTimestamp
Works on 1.9+ version. Not sure about older versions, though, but most likely should work as well.
Make a copy of your theme with a new name (themev2) - both skin and app/design, etc. Then choose the new theme in admin.
-
no, you never do that. that's really a bad way of doing itMarius– Marius2014年08月25日 20:43:38 +00:00Commented Aug 25, 2014 at 20:43
-
Why not? This way if something goes wrong with the new version, you can quickly go back to the old version. If you are using long browser-caching times and/or CDNs to serve your css (and js which might also need to be flushed/invalidated), this is by far the easiest way.The Phil Lee– The Phil Lee2014年08月25日 21:27:15 +00:00Commented Aug 25, 2014 at 21:27
-
If something goes wrong, you roll back, which should include another (the old) filename, therefore changing the configuration (read as package/theme) is not neededFabian Blechschmidt– Fabian Blechschmidt2014年08月25日 22:00:10 +00:00Commented Aug 25, 2014 at 22:00
-
I don't know how you do deployments, but this way I have to keep the old theme folder until I change the value for package/theme, or create a script that updates the value on install. Also, if I have different themes set for different periods of time they might be affected. Duplicating a lot of files is bot the easiest way by far. For example installing this: github.com/jreinke/magento-suffix-static-files is much easier. All you have to do is go an change a number in the backend after each deployment.Marius– Marius2014年08月26日 10:23:00 +00:00Commented Aug 26, 2014 at 10:23
-