English version was created automatically using Drupal module auto_node_translate and free DeepL translator.
How to solve the problem of caching images defined in Drupal template using custom twig filter
zveřejněno 2025-02-11
The goal of this article is to show an interesting problem with caching in the case of images specified in a template. This problem can be solved for example by using a custom twig filter, which we will also show.
I recently solved an interesting problem. In a template of a certain content type, an icon was defined - that is, an image path:
<img src="/{{{ base_path ~ directory }}/img/trainings/{{{ node.field_course_level.value }}.png" class="training-icon">
which in effect generates a path such as /themes/custom/mojetema/img/trainings/basic.png
The problem occurred when the image was replaced with the new version, but the browser still showed the original. It turned out that the browser still had the original image in its memory due to HTTP headers. So how do we get it to display the new file?
Solution
Probably the easiest way is to clear the browser cache, but that will only work for one particular user, but we need a solution that works for all visitors. A simple solution for cases like this is to add some unique parameter to the file path after the question mark, like a timestamp (= timestamp) or some token, like Drupal does by default for embedded images in content (equalopp.png?itok=r-01vE-R). So with timestamp, for example, like this {{ node.field_course_level.value }}.png?1739288062
It would be even smarter - rather than inserting a timestamp manually - to do this automatically. We can actually use the date the file was created as the ideal timestamp - if we upload a new file, this value will change.
Well, how to do it automatically using twig? We can extend twig with our own filters or functions. In this case, we will define a custom filter to find out the creation time of the file and then use this filter as an attribute in the file path in the template.
Custom TWIG Filter (TwigFilter)
First, we will prepare some module. In it, we then create a file namemodule.services.yml
services:
namemodule.twig_extension:
class: drupal\namemodule\TwigExtension\CustomTwigExtensions
tags:
- { name: twig.extension }
The actual class is defined in the file src/TwigExtension/CustomTwigExtensions.php as follows?
<?php
namespace Drupal\jmenomodule\TwigExtension;
use Twig\Extension\AbstractExtension;
use Twig\TwigFilter;
class CustomTwigExtensions extends AbstractExtension
{
public function getFilters()
{
return [
new TwigFilter('file_modified', [$this, 'getFileModified']),
];
}
public function getFileModified($filePath)
{
if (file_exists(DRUPAL_ROOT . $filePath)) {
return filetime(DRUPAL_ROOT . $filePath);
}
return time();
}
}
Now we can use this TWIG filter in the template as follows:
{% set file_ts = 'path/file.png' | file_modified %}
We then add the new variable after the file path
<img src="/{{{ base_path ~ directory }}/img/trainings/{{ node.field_course_level.value }}.png?{{ file_ts }}" class="training-icon">
Conclusion
The last thing will probably be to clear the Drupal cache. This will allow us to generate a new HTML file from the modified template, which will already have the modified image path, including the timestamp. These new URLs will then be loaded by the browser, which will then display the current version of the image.
Note: very similar to how TWIG functions (TwigFunction) work https://www.tothenew.com/blog/enhancing-drupal-with-custom-twig-functio…