Using a suggestion in the answer to this question, as well as this article which offers an almost identical solution, I've been trying to set up htaccess to handle an autoversioning rule on my js and css files.
The reason I want to do this is that I change them quite a lot, but still want them to be cached by browsers for aggressively long periods, without having to manually enter a new version number each time they are changed.
The method used is simple: (1) a function appends a version number to files using the date on which they were changed, on the pattern [filename].[version_number].[suffix]
, so style.css
, for instance, would become, say, style.1300638388.css
; (2) using php, the versioned number is included in the stylesheet declaration for my site's pages, and this is served to client browsers who will request a fresh copy if the versioned file name differs from that they have cached; (3) a RewriteRule in .htaccess using mod_rewrite rewrites the versioned number, reverts it to its original value and serves the updated file.
The code I'm using at each of these three stages is listed below. I'm testing this on the stylesheet in a sandbox version of my blog on http://edge.donaldjenkins.net/
1. In WordPress's functions.php file
// Allows autoversioning of css and js files
/**
* Given a file, i.e. /css/base.css, replaces it with a string containing the
* file's mtime, i.e. /css/base.1221534296.css.
*
* @param $file The file to be loaded. Must be an absolute path (i.e.
* starting with slash).
*/
function auto_version($file)
{
if(strpos($file, '/') !== 0 || !file_exists($_SERVER['DOCUMENT_ROOT'] . $file))
return $file;
$mtime = filemtime($_SERVER['DOCUMENT_ROOT'] . $file);
return preg_replace('{\\.([^./]+)$}', ".$mtime.\$1", $file);
}
2. In the <head>
portion of my blog files
<!-- Stylesheets -->
<link rel="stylesheet" href="<?=auto_version('/path/to/style.css')?>" />
3. In the .htaccess file
# Allow versioning for js and css files
RewriteEngine On
RewriteRule ^(.*)\.[\d]+\.(css|js)$ $1.$2 [L] # Strip out the version number
# End Allow versioning for js and css files
With the setup described above, pages display without any formatting, and source code of the generated page shows that the stylesheet is referenced as the versioned number—which of course doesn't exist on the server.
This would suggest that the function is correctly changing the name of the stylesheet, but that for some reason the regex pattern in the RewriteRule in .htaccess isn't catching the file name and rewriting it. In fact, it doesn't even catch it if I change it to ^style.1300638388.css$ style.css [L]
.
I've tried several patterns, to no avail, but must be missing something pretty basic.
mod_rewrite
is on on the server and runs without issues for several other RewriteRule instances.
UPDATE
The only other RewriteRule in the .htaccess
file is the standard WordPress pretty url rewrite rule. I doubt it interferes with this one, although obviously I can't easily test without the WordPress rule as this would completely break page generation:
# BEGIN WordPress
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>
# END WordPress
UPDATE 2: SOLVED
CharlesLeaf in a comment below pointed out that as the WordPress rule was before the versioning one, the latter would not be carried out. This actually was the reason and allowed me answer the question by grouping the two rules, as follows:
<IfModule mod_rewrite.c>
# Allow versioning for js and css files
RewriteEngine On
RewriteRule ^(.*)\.[\d]+\.(css|js)$ $1.$2 [L] # Strip out the version number
# End Allow versioning for js and css files
# BEGIN WordPress
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php
# END WordPress
</IfModule>