Force CSS changes to “go live” immediately

If you update your WordPress theme’s style.css, you may have noticed that you have to “force-reload” your site in your browser to see the changes. This is because your browser keeps a copy of the CSS cached on your hard drive. Depending on how your server is set up, it may not check for a new version of the stylesheet for a couple hours, or longer! And even if you force-reload to see the changes, visitors who have previously accessed your site may still get the old CSS. One way to solve this is to “version” your CSS file, by adding ?v=123 to the URL in the <link /> to your stylesheet. This is rather a pain to have to do by hand every time, so here is a much better way:

<link rel="stylesheet" href="<?php bloginfo('stylesheet_url'); echo '?' . filemtime( get_stylesheet_directory() . '/style.css'); ?>" type="text/css" media="screen, projection" />

This automatically updates the ?12345678 ending part every time you modify the file. Boom. Now everyone instantly sees your changes.

107 thoughts on “Force CSS changes to “go live” immediately

  1. Does this method even need “v=” in between the ? and the variable? Just thinkin’ of ways to simplify even further.

    Either way, this is a great method. Ever since I’ve heard about it about a year ago, I’ve used it everywhere.

  2. i like setting long future expires headers and this is an excellent solution for reloading files. can also extend out to javascript files just as easily.

  3. Would this also work for JavaScript files? I often make changes to JS and have users report that they are getting errors caused by outdated versions of functions… it’s a PITA! ;-)

  4. Yep, this will work for JavaScript. Yes, you could drop the v= part to save two characters. :-)

    i like setting long future expires headers and this is an excellent solution for reloading files.

    That’s a great tip. If you know your CSS URL will change when you update it, you can set it to be cached for a long time and reap the performance benefits.

  5. chewy22222003 says:

    I have WordPress running on Apache on it’s own server, and a separate server running Nginx that serves static files such as the CSS.

    Is there a way to check the file time stamp from the WordPress/Apache server to the Static/Nginx server over http without PHP running on the Nginx server?

    Also, since many of the static theme files run on the Nginx server, which also serves images, the Turbo function will not work in my WordPress control panel. It would be nice to be able to define a path to files for Gears to search for the files on remote, and local, servers at the same time.

  6. Nice tip. Thanks!

    Is there a reason you use:

    /style.css?v=

    instead of:

    ?v=

    ?

    The second works with child themes too and it is also a few bytes shorter. :-D

  7. (Repeating last comment without the PHP tags.)

    Nice tip. Thanks!

    Is there a reason you use:

    bloginfo(‘template_url’) + /style.css?v=

    instead of:

    bloginfo(‘stylesheet_url’) + ?v=

    ?

    The second works with child themes too and it is also a few bytes shorter. :-D

  8. @demetris: you’re right, that should actually be calling bloginfo(’stylesheet_url’). Also, instead of using the TEMPLATEPATH constant, get_stylesheet_directory() would be much better, since it takes into account any plugins that hook into the ‘stylesheet_directory’ hook.

  9. @Will: There is a STYLESHEETPATH constant too, whose value is get_stylesheet_directory().

    (So, if stylesheet_url is used, the file to check the modification time for is: STYLESHEETPATH + /style.css)

  10. @demetris: sure, but you still have the same problem of bypassing any plugins that may be using the ‘stylesheet_directory’ hook to pull the stylesheet from some place else entirely.

  11. Or, now that I think about it… you could just add a filter on the ‘stylesheet_uri’ hook to append the timestamp. Then it would work on any theme without modification, provided that they are properly calling bloginfo(‘stylesheet_url’), which I think most do.

    add_filter('stylesheet_uri', create_function('$s', 'return $s . "?" . filemtime( get_stylesheet_directory() . "style.css"");'))

    Yes, yes, there are a number of different ways you could do it. :) Regardless of what method you use, a great idea. Thanks Mark!

  12. Pim says:

    I believe according to http spec, browsers should not cache URI’s with GET parameters in it. Not sure what browser implement this correctly.

    A solution would be to embed the file version number in the filename itself. E.g.: my-css-file.v123.css.

  13. mark says:

    hmmm, strange
    does not work for me (tested in Chrome 2 and FF)

    before:

    after:

    but the old css is still used until i hit [F5] (manuel forced refresh)

    any ideas why?

  14. This is not a very good solution. You lose the advantage of caching which is one of the benefits of having an external stylesheet. Now your stylesheet has to be downloaded and parsed on EVERY PAGE LOAD which means longer page load and rendering times. This hurts your users’ experience on your site. It also means your eating unnecessary bandwidth. And for what? So your users get a new styleheet IF you happened to have made changes to it recently? Does your stylesheet really change THAT often? Is caching really that much of a problem? Almost certainly not.

    Browsers caching stylesheets is rarely a real problem and this solution is overkill. I definitely don’t recommend it to anyone who doesn’t have a VERY dynamic stylesheet (i.e. ones changes very, very frequently. I mean every few minutes or so).

  15. John, are you referring to the solution in the very first post? If so, it’ll only invalidate the cache if the style sheet is modified. If you only modify it every six months, then for those six months, the address to the style sheet will remain unchanged and it’ll be cacheable.

    A change to the style sheet will change the modified time appended to the URL, which the browser sees as a “new” address and so will load the style sheet freshly from the server.

  16. mark says:

    so how can it be, that i dont see any effect in my browsers?
    they still use the same cached file, even
    if layout.css?1 is now layout.css?2

    any ideas?

    • Jeff says:

      I see the same problem in IE7, it’s not working. I have to manually visit the css file’s url then it works.

  17. I have to agree with Ozh, “There’s still a gotcha: it seems that some browsers don’t cache files with a query string”…

    Simplest solution we’ve used is to version number your CSS, so it might be

    master1.css

    after some changes you don’t want cached, name it:

    master1.1.css

    Its a whole different file, and will force your browser to load it.

    Good luck.

  18. Oh, yeah, oh, yeah, this is cool, I marked my files using time(), but this is much better, as this only forces a reload when the file changes.

    But isn’t there a way to make the browser “do the right thing” via .htaccess file? I think it would be better.

  19. Good grief, this is one of the most useful tips I have ever come across! Why didn’t I learn this years ago?

    Massive thanks.

  20. Franz Bodmer says:

    Thank you, thank you, thank you. You have no idea of how much grief this has caused me with different people being served by different ISPs.

  21. Z says:

    Great post. Just curious how would this work if u wanted to load multiple stylesheets? doesnt stylesheet_url direct you to the main style.css of the parent theme?

  22. PHEW!!! thank you Mark, I have this problem about editing my CSS live and the edited CSS wont take effect everytime i refresh… you’re my life saver :D

  23. WordPress enqueue_style function outputs css with time stamp ( using filemtime( get_stylesheet….)
    like this
    href=’http://127.0.0.1/brand/wp-content/themes/brand/css/default-layout.css?ver=1294031380′

    and posted tutorial outputs like this
    href=”http://127.0.0.1/brand/wp-content/themes/brand/style.css?1309415833″

    no VER=

    which way is better, if any?

    • Either way works just as well as the other; the point is that the browser sees each as a specific URL so that when the string of numbers changes, it’s recognized as another distinct URL. This results in the style sheets being loaded fresh from the server.

  24. richard says:

    Perfecto … muy interesante.

    Ya estaba loco con el CSS y la personalización de un fan box de Facebook

  25. YOU HAVE ABSOLUTELY HOW MUCH THIS HELPED ME.. WordPress was taking 5-10 minutes to reflect CSS changes no matter WHAT I did, even what computer or theme I used. It was driving me insane. This fixed it. It should be added to WordPress.. Thank you so much!

  26. Frazer Kirkman says:

    thank you.

    I just put a large site live, and when I noticed how badly the old css mashed the layout, I went in to adrenaline mode, and you save the site with only 20 seconds of mash-d time.

    Thanks. Hopefully not to many people saw it.

    I’ll use this from now on

  27. Thank you so much for this, I’ve been updating the css on my site like mad today and panicked when it wasn’t reloading, even on a force-refresh.

  28. IQ says:

    Sorry I am a newbie.

    Please can you tell where to add this code – In header.php or style.css ? Also which part of the file ?

    Thank you very much
    IQ

  29. Jake Jackson says:

    thanks for the tip… I used this style in my non-wp site:

    <link rel="stylesheet" type="text/css" href="/css/home.css?”>

    That way it uses the file modified time of the stylesheet and only changes the get request param when the file is changed. However if browsers really don’t cache any get requests, then I suppose you might as well just use ANYTHING in the query string and it will work in the same non-efficient way :/

    • Jake Jackson says:

      oops, the php code was stripped out of my comment. I guess you’ll never know what i posted! lol sorry

Comments are closed.