Vorlagen ohne Logik

Layout, Template, Partial: wer wen einbindet

Die drei Dateiarten sind in zwei Minuten unterschieden. Die Stunden gehen später drauf, wenn eine Vorlage nicht greift und niemand weiß, aus welchem Pfad sie tatsächlich kommt.

KI-generiertDieses Bild wurde mit KI erzeugt · Yves Hoppe / KI / cmt
Seit 1997 am Markt Kleine Gruppen Präsenz und Live-Online Zertifizierte Trainer
Worum es geht

Die eigene Vorlage wird gefunden, benutzt wird trotzdem die alte

Fluid sucht seine Dateien nicht in einem Verzeichnis, sondern in einer nummerierten Liste von Verzeichnissen, und es gewinnt der Treffer mit der höchsten Nummer. Eine Extension liefert ihre Vorlagen unter einem niedrigen Schlüssel, deine eigenen kommen darüber. Wer diese Mechanik nicht kennt, legt seine Datei an einen Pfad, den zwar jemand einmal konfiguriert hat, der aber unter dem der Extension liegt, und wundert sich über die ausbleibende Wirkung.

Der übliche Ausweg macht es schlimmer. Entweder wird das komplette Vorlagenverzeichnis einer Extension kopiert, womit auch alle Dateien mitwandern, die man gar nicht ändern wollte und die künftige Korrekturen nie mehr erhalten. Oder es wird direkt in der fremden Extension editiert, und der nächste Composer-Lauf setzt die Datei zurück, gern unbemerkt kurz vor einem Termin.

Die zweite Baustelle ist Logik, die ins Template wandert. Fluid hat bewusst keinen vollen Zugriff auf PHP: Du kannst keine beliebige Methode mit Argumenten aufrufen, ein Ausdruck wie {objekt.name} funktioniert nur über einen Getter, und Bedingungen können vergleichen, aber nicht rechnen wie eine Programmiersprache. Wer trotzdem alles im Template löst, endet bei verschachtelten Bedingungen, die niemand mehr liest und die kein Test je erfasst.

KI-generiertDieses Bild wurde mit KI erzeugt · Yves Hoppe / KI / cmt
Der Aufbau im Detail

Ein Aufruf, Bestandteil für Bestandteil

Der Aufruf eines Partials enthält fast alles, was man über Fluid wissen muss: Namensräume, Argumente und die Auflösung über eine Pfadliste.

Der Aufbau

<f:render partial="Teaser/Card" arguments="{item: element}" />
  1. 01 Der Namensraum <f:

    Das Kürzel f steht für den Standardnamensraum, der ohne Anmeldung in jedem Template verfügbar ist. Eigene und fremde ViewHelper bekommen ein anderes Kürzel, das am Dateianfang oder als Attribut am Wurzelelement bekannt gemacht wird. Fehlt diese Zeile, gibt Fluid den Aufruf als Text aus, statt zu meckern.

  2. 02 Der ViewHelper render

    Derselbe ViewHelper bindet je nach Argument ein Partial oder einen Abschnitt ein. Mit section holt er einen Abschnitt aus der eigenen Datei, und genau darüber greifen Layout und Template ineinander.

  3. 03 Die Art des Bausteins partial=

    Ein Partial ist eine eigene Datei mit eigenem Gültigkeitsbereich, ein Abschnitt bleibt in der Datei, in der er steht, und sieht deren Variablen. Diese Entscheidung ist der eigentliche Unterschied zwischen den beiden.

  4. 04 Der Name ohne Pfad und ohne Endung "Teaser/Card"

    Angegeben wird der Name relativ zum Partial-Verzeichnis, Unterordner mit Schrägstrich, die Dateiendung lässt Fluid weg. Gesucht wird in allen konfigurierten Verzeichnissen, beginnend beim höchsten Nummernschlüssel.

  5. 05 Die Übergabe {item: element}

    Ein Partial sieht ausschließlich, was hier steht. Das ist Absicht und der Grund, warum Partials wiederverwendbar bleiben. Wer stattdessen alle Variablen durchreicht, handelt sich genau die Kopplung ein, die das Partial vermeiden sollte.

Wenn es nicht funktioniert

Das siehst du

Deine Änderung ist im Frontend nicht zu sehen, die bearbeitete Datei ist aber sicher die richtige.

Warum

Aus einem Verzeichnis mit höherem Nummernschlüssel kommt eine gleichnamige Datei und gewinnt.

Was hilft

Im Modul TypoScript unter Aktives TypoScript die Pfadlisten der betroffenen Konfiguration ansehen und den eigenen Schlüssel über den fremden legen.

Das siehst du

Nach dem Eintragen des eigenen Pfads fehlen plötzlich Standardelemente in der Ausgabe.

Warum

Die Pfadliste wurde komplett neu gesetzt statt um einen Schlüssel ergänzt, damit sind die mitgelieferten Verzeichnisse verschwunden.

Was hilft

Nur den eigenen Schlüssel setzen, etwa die 20 neben der vorhandenen 0 und 10, und die bestehenden Nummern unangetastet lassen.

Das siehst du

Auf der Seite stehen sichtbare HTML-Tags mitten im Text.

Warum

Fluid maskiert jede Ausgabe. Das ist der Normalfall und kein Fehler.

Was hilft

Für Inhalte aus dem Rich-Text-Editor den ViewHelper für HTML-Ausgabe verwenden, der den Text zusätzlich durch die konfigurierte Nachbearbeitung schickt. Die rohe Ausgabe nur dort einsetzen, wo der Inhalt nicht aus einer Eingabe stammt.

Das siehst du

Eine Variable ist im Template gefüllt, im Partial aber leer.

Warum

Partials erben nichts. Sie kennen nur die Werte, die im Argumente-Attribut stehen.

Was hilft

An beiden Stellen die vorhandenen Variablen ausgeben lassen und den fehlenden Wert gezielt übergeben, statt pauschal alles durchzureichen.

Das siehst du

Ein eigener ViewHelper erscheint als Text im Quelltext der Seite.

Warum

Der Namensraum ist in dieser Datei nicht bekannt gemacht, deshalb behandelt Fluid den Aufruf als gewöhnliches Markup.

Was hilft

Die Namensraumzeile an den Dateianfang setzen oder das entsprechende Attribut am Wurzelelement ergänzen. In Partials gilt sie nicht automatisch mit.

Fünf Stationen, bis aus einer Fluid-Datei fertiges HTML wird

  1. 01 TypoScript legt fest, welche Pfadlisten für Layouts, Templates und Partials gelten.
  2. 02 Fluid nimmt aus jeder Liste den Treffer mit dem höchsten Nummernschlüssel.
  3. 03 Das Template meldet über den Layout-ViewHelper, welches Gerüst es benutzen will.
  4. 04 Das Layout ruft die benannten Abschnitte ab und setzt sie an ihre Stelle.
  5. 05 ViewHelper und Partials füllen den Inhalt, jede Ausgabe wird dabei maskiert.
Was du mitnimmst

Was du danach in der Vorlagenschicht sicher entscheidest

Die Templateschicht wird beherrschbar, sobald zwei Fragen jederzeit beantwortbar sind: Woher kommt die Datei, die gerade gerendert wird, und welche Variablen stehen in ihr zur Verfügung. Alles andere folgt daraus.

Zuständigkeiten sauber trennen

Das Layout enthält das umgebende Gerüst und ruft benannte Abschnitte ab. Das Template meldet, welches Layout es benutzt, und definiert diese Abschnitte. Ein Partial ist eine eigene Datei für einen Ausschnitt, der an mehreren Stellen gebraucht wird.

Variablen nachsehen statt vermuten

Ein ViewHelper zum Ausgeben aller vorhandenen Werte beendet die meisten Diskussionen in zehn Sekunden. Besonders lohnend ist der Blick, bevor du eine Bedingung schreibst, denn ein leerer Wert und ein nicht vorhandener Wert sehen im Ergebnis gleich aus.

Tag- und Inline-Schreibweise bewusst wählen

Beide erzeugen dasselbe. Die Tag-Schreibweise ist lesbarer, sobald ein Block Inhalt umschlossen wird, die Inline-Schreibweise gehört in Attribute und in kurze Verkettungen, bei denen ein Wert durch mehrere Formatierungen läuft.

Pfadlisten ergänzen statt ersetzen

Du setzt einen eigenen Schlüssel mit einer höheren Nummer und lässt die vorhandenen Nummern stehen. Damit überlagerst du genau die Dateien, die du selbst mitbringst, und alles andere kommt weiter aus der Extension, inklusive späterer Korrekturen.

Maskierung als Normalfall verstehen

Fluid maskiert jede Ausgabe, deshalb erscheint HTML aus einem Datenfeld als sichtbarer Text. Für Inhalte aus dem Rich-Text-Editor gibt es den passenden Format-ViewHelper, die rohe Ausgabe gehört nur an Stellen, deren Inhalt nicht aus einer Eingabe stammt.

Eigenen ViewHelper schreiben, wenn Logik drängt

Sobald eine Bedingung über zwei Zeilen wächst oder derselbe Kniff im dritten Template auftaucht, gehört er in eine kleine PHP-Klasse. Die ist testbar, hat einen Namen und lässt sich an einer Stelle korrigieren.

KI-generiertDieses Bild wurde mit KI erzeugt · Yves Hoppe / KI / cmt

Drei Dateiarten, drei Aufgaben

Die Verzeichnisse liegen in einer Extension unter Resources/Private und heißen Layouts, Templates und Partials. Das Layout enthält das umgebende Gerüst, also Kopf, Fuß und Grundraster, und ruft an den passenden Stellen benannte Abschnitte ab. Das Template meldet am Dateianfang, welches Layout es benutzt, und definiert genau diese Abschnitte. Fehlt die Layout-Angabe, wird der gesamte Inhalt der Templatedatei ausgegeben und die Abschnitte werden ignoriert.

Ein Partial ist eine eigene Datei mit eigenem Gültigkeitsbereich. Es kennt keine Variablen der aufrufenden Datei, sondern nur die übergebenen. Ein Abschnitt dagegen bleibt in der Datei, in der er steht, und sieht deren Werte. Daraus folgt die Faustregel: Was an mehreren Stellen gebraucht wird, wird ein Partial, was nur die eigene Datei strukturiert, bleibt ein Abschnitt.

Die Verwechslungsgefahr zwischen beiden ist hoch, weil derselbe ViewHelper sie einbindet. Der Unterschied liegt allein im Argument, und er ist der Grund für die häufigste Überraschung: Nach dem Auslagern eines Abschnitts in ein Partial sind plötzlich die Hälfte der Werte leer.

Woher die Variablen kommen und wie du nachsiehst

Rendert die Seite über das TypoScript-Objekt FLUIDTEMPLATE, kommen die Werte aus drei Quellen: aus den dort gesetzten Variablen, aus den Datenaufbereitungen, die Datensätze einsammeln und als Liste bereitstellen, und aus den Einstellungen, die meist aus den Constants oder aus den Settings eines Site Sets gespeist werden. Der aktuelle Datensatz steht zusätzlich als eigene Variable bereit, bei einer Seite ist das der Seitendatensatz mit allen Feldern.

Bei einer Extbase-Erweiterung ist es einfacher: Dort weist der Controller genau die Werte zu, die im Template ankommen sollen. Wenn etwas fehlt, fehlt es im Controller, und kein Kniff im Template holt es nach.

Statt zu vermuten, lohnt in beiden Fällen die Ausgabe aller vorhandenen Werte über den Debug-ViewHelper. Das Ergebnis beantwortet fast immer beide Fragen auf einmal, nämlich ob der Wert überhaupt existiert und wie er heißt, denn Tippfehler in Variablennamen erzeugen in Fluid keine Fehlermeldung, sondern eine leere Ausgabe.

Die ViewHelper, die du täglich brauchst

Für Bedingungen gibt es f:if mit den Zweigen f:then und f:else, für Wiederholungen f:for, das über eine Liste läuft und über das Argument iteration auf Wunsch mitliefert, ob der aktuelle Durchlauf der erste oder der letzte ist. Für Verweise auf Seiten gibt es f:link.page und, wenn nur die Adresse gebraucht wird, f:uri.page, für die volle Linkauswertung inklusive Dateien und externer Ziele f:link.typolink. Bilder laufen über f:image, das Breite, Höhe und eine Beschnittvariante entgegennimmt und die Datei bei Bedarf erzeugt. Und f:debug gibt aus, was in der Datei tatsächlich ankommt.

Dieselbe Sache lässt sich als Tag oder inline schreiben. Die Tag-Schreibweise ist lesbarer, sobald ein Block umschlossen wird. Die Inline-Schreibweise gehört in Attribute, wo ein Tag gar nicht stehen kann, und in kurze Ketten, bei denen ein Wert nacheinander durch mehrere Formatierungen läuft. Beides mischt sich in derselben Datei problemlos, nur innerhalb einer Zeile wird es schnell unleserlich.

Die vollständige Liste steht in der ViewHelper-Referenz mit allen Argumenten. Sie einmal am Anfang zu überfliegen lohnt sich, weil vieles, was man sonst selbst zusammenbaut, dort schon als fertiger ViewHelper steht, etwa Formatierungen für Datum, Zahlen und Währungen oder das Kürzen von Text auf eine Zeichenzahl.

Wo die Templates gesucht werden

Die drei Pfadlisten für Layouts, Templates und Partials werden im TypoScript als nummerierte Einträge gesetzt. Fluid geht sie von der höchsten Nummer abwärts durch und nimmt den ersten Treffer für den gesuchten Dateinamen. Das bedeutet: Du überlagerst einzelne Dateien, du ersetzt kein Verzeichnis. Eine Datei, die du nicht mitbringst, kommt weiter aus der Extension, samt aller künftigen Korrekturen von dort.

Konfiguriert wird das an mehreren Stellen, und diese Unterscheidung erspart viel Sucherei. Für die Seite selbst stehen die Listen am FLUIDTEMPLATE-Objekt unterhalb von page. Für die Inhaltselemente aus der Systemextension fluid_styled_content hängen sie an deren eigener Konfiguration unter lib. Wer die Vorlage eines Inhaltselements anpassen will und die Pfade der Seite ändert, ändert die falsche Liste.

Für die Ablage der eigenen Dateien gilt dieselbe Regel wie für den Rest der Website. Der richtige Ort ist eine eigene Extension, nicht ein Verzeichnis neben der Installation und schon gar nicht die fremde Extension. Bearbeitete Dateien unterhalb von vendor sind beim nächsten Composer-Lauf weg, ohne dass jemand gefragt wird.

Fluid hat bewusst keinen vollen Zugriff auf PHP

Das ist kein Mangel, sondern eine Entscheidung. Templates werden von Menschen bearbeitet, die kein PHP schreiben, und sie werden aus Dateien geladen, die in vielen Installationen editierbar sind. Deshalb lässt sich in Fluid keine beliebige Methode mit Argumenten aufrufen, ein Punktzugriff funktioniert nur über einen Getter, und die Ausgabe wird standardmäßig maskiert. Was ein Template kann, ist damit von außen absehbar.

Die Grenze verläuft entlang einer einfachen Frage. Was angezeigt wird, entscheidet die Seite, die die Daten liefert, also der Controller oder die Datenaufbereitung im TypoScript. Wie es angezeigt wird, entscheidet das Template. Eine Bedingung, die im Template auswählt, welcher Datensatz überhaupt geholt wird, sitzt auf der falschen Seite dieser Grenze.

Für alles dazwischen gibt es den eigenen ViewHelper: eine PHP-Klasse im Verzeichnis Classes/ViewHelpers der eigenen Extension, mit initializeArguments zum Deklarieren der Argumente und render für die Ausgabe. Danach hat der Kniff einen Namen, eine Datei und eine Stelle, an der er korrigiert wird, und er lässt sich testen, was für eine verschachtelte Bedingung im Template grundsätzlich nicht gilt.

Dazu passende Kurse

Weil die beiden Schichten nur zusammen Sinn ergeben, lohnt es sich, Fluid und TypoScript mit Trainer statt getrennt zu erarbeiten.

Wissen prüfen

Wie sicher bist du beim Thema wirklich?

Lesen fühlt sich schnell nach Können an. Ein kurzer Test zeigt dir, was davon schon sitzt und wo sich ein Kurs lohnt. Kostenlos, ohne Anmeldung, mit einer Erklärung zu jeder Antwort.

Sehr kompetente und freundliche Trainerin. Die Inhalte wurden gut strukturiert und anhand von anschaulichen Beispielen vermittelt.
TYPO3 Training für Redakteure - Einführung

Häufige Fragen

Wann nehme ich ein Partial und wann einen Abschnitt?
Ein Abschnitt bleibt in der Datei, in der er steht, und sieht deren Variablen. Ein Partial ist eine eigene Datei und sieht ausschließlich, was du ihm übergibst. Was mehrfach gebraucht wird, gehört ins Partial, was nur die eigene Datei gliedert, bleibt Abschnitt.
Warum werden meine HTML-Tags als Text ausgegeben?
Weil Fluid jede Ausgabe maskiert. Für Inhalte aus dem Rich-Text-Editor gibt es einen eigenen Format-ViewHelper, der zusätzlich die konfigurierte Nachbearbeitung anwendet. Die ungefilterte Ausgabe solltest du nur dort einsetzen, wo der Inhalt nicht aus einer Eingabe stammt.
Kann ich in Fluid PHP-Funktionen aufrufen?
Nein, das ist bewusst nicht vorgesehen. Zugriff auf Objekte gibt es nur über Getter, beliebige Methodenaufrufe mit Argumenten gibt es nicht. Was du brauchst, schreibst du als eigenen ViewHelper in eine PHP-Klasse deiner Extension, dort ist es testbar und an einer Stelle änderbar.
Muss ich für ein eigenes Design alle Templates kopieren?
Nein, und das ist der Sinn der nummerierten Pfadlisten. Du legst nur die Dateien an, die du wirklich änderst, und gibst deinem Verzeichnis eine höhere Nummer. Alle anderen Dateien kommen weiter aus der Extension und bekommen deren Korrekturen automatisch mit.
Persönlich für dich da

Deine Ansprechpartner

Du bist dir nicht sicher, welcher Kurs oder welches Level zu dir passt? Wir beraten dich persönlich und kostenlos.

Yves Hoppe

Yves Hoppe

Weiterbildung & Beratung

Hilft dir, aus dem TYPO3-Programm den passenden Kurs für deinen Stand zu finden.

Norbert Jansen

Norbert Jansen

Beratung & Inhouse

Plant mit dir Inhouse-Trainings, die auf eure Abläufe und euren Datenbestand zugeschnitten sind.

Vorlagen, die ein Update überstehen

Bei cmt arbeitest du die Aufteilung in Layout, Template und Partial an einer laufenden Installation durch und siehst dabei, aus welchem Verzeichnis eine Datei tatsächlich kommt.