Drupal Preprocess-Hooks: Warum der `url.path`-Cache-Kontext wichtig ist
Wenn Sie die Ausgabe in einem Preprocess-Hook basierend auf der aktuellen Route oder dem Pfad ändern, müssen Sie dem Render-Cache von Drupal auch mitteilen, was diese Ausgabe variiert. Andernfalls kann das erste gerenderte Ergebnis zwischengespeichert und überall wiederverwendet werden.
Die Situation
Betrachten Sie ein benutzerdefiniertes Preprocess für den Branding-Block, der auf Blog-Nodes einen anderen Seitennamen anzeigt:
getRouteName();
// Prüfen, ob wir uns auf einer Blog-Seite befinden
if ($route_name === 'entity.node.canonical') {
$node = $route_match->getParameter('node');
if ($node && $node->bundle() === 'blog') {
// Auf Blog-Seiten den Seitennamen zu "HELLO WORLD" ändern
$variables['site_name'] = 'HELLO WORLD';
}
}
// Auf der Startseite und anderen Seiten den ursprünglichen Seitennamen beibehalten
}
Ohne die Zeile, die den Cache-Kontext hinzufügt ($variables['#cache']['contexts'][] = 'url.path';
), kann Drupal die erste gerenderte Version (z. B. die Blog-Version) zwischenspeichern und auf jeder Seite wiederverwenden. Deshalb sahen Sie überall denselben Text.
Warum passiert das?
- Render-Caching: Drupal speichert Render-Arrays zur Leistungssteigerung zwischen.
- Variierende Ausgabe: Wenn sich die Ausgabe nach Pfad oder Route ändert, muss der Cache-Schlüssel diese Variabilität enthalten.
- Cache-Kontexte: Das Hinzufügen von
url.path
(oder einem spezifischeren Kontext) teilt Drupal mit, separate Cache-Variationen pro Pfad beizubehalten.
Gilt das für alle Preprocess-Hooks?
Ja, die Regel gilt für jede renderbare Ausgabe, die variiert. Preprocess-Hooks modifizieren oft Render-Arrays oder Template-Variablen, die Teil des Render-Caches werden. Wenn Ihre Logik variiert nach:
- Pfad oder Route →
url.path
oderroute
hinzufügen - Aktueller Benutzer →
user
(oder granularere Kontexte wieuser.roles
) hinzufügen - Sprache →
languages:language_interface
hinzufügen - Theme oder Breakpoint →
theme
,responsive_image_style
usw. hinzufügen
Preprocess selbst ist nichts Besonderes; entscheidend ist, ob das resultierende Render-Array zwischen verschiedenen Anfragen unterschiedlich zwischengespeichert werden sollte. Wenn die Ausgabe variiert, deklarieren Sie die richtigen Cache-Kontexte.
Auswahl des richtigen Cache-Kontexts
- Präzision bevorzugen: Wenn Sie von einem kanonischen Node abhängen, ziehen Sie
route
anstelle vonurl.path
in Betracht, um unnötige Cache-Fragmentierung zu vermeiden (z. B. Query-Strings oder Aliase). - Entitätsbasierte Blöcke: Wenn Sie von einer Entität (wie einem Node) abhängen, fügen Sie Cache-Abhängigkeiten hinzu, damit Bearbeitungen korrekt bereinigt werden:
$variables['#cache']['tags'][] = 'node:' . $node->id();
- Max-age: Behalten Sie
max-age
auf dem Standardwert (permanent), es sei denn, die Ausgabe läuft wirklich ab.
Sicherere Alternative: Ableiten vom Render-Array
Anstatt Globals zu verwenden, können Sie auch Cacheability-Metadaten mit CacheableMetadata
anhängen, um Kontexte und Tags sicher zusammenzuführen:
addCacheContexts(['route']);
$route_match = \Drupal::routeMatch();
if ($route_match->getRouteName() === 'entity.node.canonical') {
$node = $route_match->getParameter('node');
if ($node && $node->bundle() === 'blog') {
$variables['site_name'] = 'HELLO WORLD';
$cacheable->addCacheTags(['node:' . $node->id()]);
}
}
$cacheable->applyTo($variables);
}
Checkliste
- Ändert sich die Ausgabe je nach Pfad oder Route? Fügen Sie
url.path
oderroute
hinzu. - Hängt sie von einer Entität ab? Fügen Sie Cache-Tags für diese Entität hinzu.
- Variiert sie je nach Benutzer oder Sprache? Fügen Sie die passenden Kontexte hinzu.
- Halten Sie
max-age
hoch; verlassen Sie sich für die Invalidierung auf Tags.
Fazit
Ja – wenn Ihre Preprocess-Logik die Ausgabe pro Seite ändert, müssen Sie die entsprechenden Cache-Kontexte deklarieren. Andernfalls liefert Drupal gerne dasselbe zwischengespeicherte Ergebnis überall aus.