Jak vyřešit problém cachování obrázků definovaných v Drupal šabloně pomocí vlastního twig filtru

Cílem tohoto článku je ukázat zajímavý problém s cachováním v případě obrázků zadaných v šabloně. Tento problém lze vyřešit například pomocí vlastního twig filtru, což si také ukážeme.

Nedávno jsem řešil zajímavý problém. V šabloně jistého content typu byla definovaná ikona – tedy cesta k obrázku:

<img src="/{{ base_path ~ directory }}/img/trainings/{{ node.field_course_level.value }}.png" class="training-icon">

což ve výsledku vygeneruje cestu např. /themes/custom/mojetema/img/trainings/basic.png

Problém nastal, když se obrázek nahradil novou verzí, ale v prohlížeči se stále ukazovala původní. Ukázalo se, že původní obrázek má prohlížeč stále ve svojí paměti díky HTTP hlavičkám. Jak ho tedy přinutit zobrazit nový soubor?

 

Řešení

Samozřejmě nejjednodušší je vymazat cache prohlížeče, to ale bude fungovat jen u jednoho konkrétního uživatele, my ale potřebujeme řešení funkční pro všechny návštěvníky. Jednoduché řešení pro podobné případy je přidat do cesty k souboru za otazník nějaký unikátní parametr, třeba časové razítko (= timestamp) nebo nějaký token, tak jak to například dělá standardně Drupal pro vložené obrázky v obsahu (equalopp.png?itok=r-01vE-R). S timestamp tedy např. takto {{ node.field_course_level.value }}.png?1739288062

Ještě chytřejší - než vkládat ručně nějaký timestamp - by bylo, aby se to dělalo automaticky. Jako ideální časové razítko můžeme vlastně použít datum vytvoření souboru - pokud nahrajeme nový soubor, tato hodnota se změní.

Jenže jak to udělat automaticky pomocí twigu? Twig si můžeme rozšířit pomocí vlastních filtrů nebo funkcí. V tomto případě si nadefinujeme vlastní filtr, který zjistí zjistí čas vytvoření souboru a v šabloně tento filtr pak použijeme jako atribut v cestě souboru.

 

Vlastní TWIG filtr (TwigFilter)

Nejdříve si připravíme nějaký modul. V něm si pak vytvoříme soubor jmenomodulu.services.yml

services:
  jmenomodulu.twig_extension:
    class: Drupal\jmenomodulu\TwigExtension\CustomTwigExtensions
    tags:
      - { name: twig.extension }

samotnou třídu si definuje v souboru src/TwigExtension/CustomTwigExtensions.php a to následovně?

<?php
namespace Drupal\jmenomodulu\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 filemtime(DRUPAL_ROOT . $filePath);
        }

        return time();
    }

}

 

Nyní tento TWIG filter můžeme použít v šabloně následovně:

{% set file_ts = 'cesta/k/souboru.png' | file_modified %}

Novou proměnnou pak přidáme za cestku k souboru

<img src="/{{ base_path ~ directory }}/img/trainings/{{ node.field_course_level.value }}.png?{{ file_ts }}" class="training-icon">

 

Závěr

Poslední věc bude pravděpodobně vyčistit Drupal cache. Díky tomu se nám z upravené šablony vygeneruje nový HTML soubor, kde už bude upravená cesta k obrázku včetně timestampu. Tyto novu URL pak načtě prohlížeč, který tak zobrazí aktuální verzi obrázku.

 

Pozn.: velmi podobně se pak pracuje s TWIG funkcemi (TwigFunction) https://www.tothenew.com/blog/enhancing-drupal-with-custom-twig-functio…