Problem/Motivation
When working on a module that uses File Entity to handle media assets we've discovered that currently, there no way to bypass browser file cache in theme_image and theme_image_style. File Entity provides users with a way to replace their file with a new one, without changing the name of the file. Because filename remains the same, it's still cached in browser and will not show up until clearing page cache with CTRL+R.
This might be fine and we're used to it on the user facing site, but it might confuse authors who just replaced their image with a new one, and it's not showing the latest image in admin interface. It would be nice to have a way to bust browser cache that works with Drupal's theming functions, so we don't reinvent the wheel.
Proposed resolution
In order to bust browser cache we might add some query parameter to achieve a unique URL. This hard to do with theme_image code because of file_create_url.
Any image path passed to theme_image is passed throw file_create_url as seen below:
function theme_image($variables) {
$attributes = $variables['attributes'];
$attributes['src'] = file_create_url($variables['path']);
...
You could construct a URL like public://filename.jpg?hash=1234567 and pass it to theme_image to get a fresh image when you really need it, but your URL will be encoded inside file_create_url using drupal_encode_path($uri)
which will encode your "?" and "=" and will render your URL incorrectly. To bypass this you could send an absolute URL to theme_image, but then you have to construct your absolute URL yourself everywhere you need it, and then you will have to fix theme_image_style which already constructs an absolute URL with the same file_create_url and lacks a cache bust token option.
I suggest having a way to indicate that a cache bust token should be appended to the passed 'path' parameter.
Here is a way to do that:
function theme_image($variables) {
$attributes = $variables['attributes'];
$attributes['src'] = file_create_url($variables['path']);
// Provide a way to bust browser file cache.
if (isset($variables['cache']) && !$variables['cache']) {
$attributes['src'] = $attributes['src'] . (strpos($attributes['src'], '?') !== FALSE ? '&' : '?') . 'ihash=' . time();
}
foreach (array('width', 'height', 'alt', 'title') as $key) {
if (isset($variables[$key])) {
$attributes[$key] = $variables[$key];
}
}
return '<img' . drupal_attributes($attributes) . ' />';
}
Then we can use it like this:
$variables = array(
'path' => 'path/to/img.jpg',
'alt' => 'Test alt',
'title' => 'Test title',
'width' => '50%',
'height' => '50%',
'attributes' => array('class' => 'some-img', 'id' => 'my-img'),
// Bypass cache
'cache' => FALSE,
);
$img = theme('image', $variables);
This should not affect any image rendering when 'cache' parameter is not set, and will allow to enable cache busting form both theme_image and theme_image_style as theme_image_style will call theme_image.
In order to be able to use it with image formatter we also need to modify image formatter, otherwise people will have to create their own image formatter to use that option.
Remaining tasks
Patch to follow
User interface changes
Not applicable
API changes
You can use 'cache' parameter set to FALSE to bust browser cache like this:
$variables = array(
'path' => 'path/to/img.jpg',
'alt' => 'Test alt',
'title' => 'Test title',
'width' => '50%',
'height' => '50%',
'attributes' => array('class' => 'some-img', 'id' => 'my-img'),
// Bypass cache
'cache' => FALSE,
);
$img = theme('image', $variables);