Flexible Container und Grids für TYPO3, Teil drei

|David Steeb
Wie man komplexe Seitenlayouts und Teil-Strukturen in TYPO3 implementiert

Fortgeschrittenes Beispiel: Wie man komplexe Untereinheiten zu einer Seite hinzufügt. In Teil 1 dieser Serie haben wir unsere Container-Erweiterung vorgestellt (und wann man sie nicht verwenden sollte!). Wir sprachen darüber, warum wir sie erstellt haben und wie man einfache Containerelemente zur Strukturierung des Inhalts hinzufügen kann. In Teil 2 führten wir durch ein kurzes Beispiel: Hinzufügen einer einfachen zweispaltigen Unterstruktur zu einer Seite und Speichern von Inhaltselementen darin.

In diesem dritten Beitrag möchte ich einige fortgeschrittene Anwendungsfälle zeigen, in denen Containerelemente uns dabei helfen, eine saubere und intuitive Benutzeroberfläche für Redakteure zu schaffen, und warum wir die „core-nahe“ Art und Weise lieben, wie Containerelemente von unserer Erweiterung erstellt werden (Stichwort: sauberer Code und einfachere, weniger riskante Upgrades).

Fortgeschrittenes Anwendungsbeispiel für Container

Die Notwendigkeit, Unterabschnitte einer Seite in einem zweispaltigen Layout anzuzeigen, ist ein offensichtlicher Anwendungsfall für jede multi-column Extension. Bei den Projekten, die wir bei b13 in Angriff nehmen, stoßen wir im Frontend regelmäßig einige komplexe „Element-Kombination“-Anforderungen. Unsere Designer scheinen auch ein Händchen dafür zu haben, uns ständig herauszufordern und bis an die Grenzen des Möglichen zu gehen. Als TYPO3-Integratoren sind wir bestrebt, flexible Backend- und Inhaltselementstrukturen zu schaffen. Wir wollen alle möglichen gewünschten Kombinationen von Inhaltstypen zulassen, die wir (oder unsere Designer) sehen wollen, und gleichzeitig die verfügbaren Optionen und Layouts auf ein Minimum beschränken. Wir haben festgestellt, dass zu viel Flexibilität dazu führt, dass Redakteure das Design (unbeabsichtigt) durcheinander bringen können, insbesondere bei großen Teams, die in einem TYPO3-Backend arbeiten. Wir versuchen, die Auswahlmöglichkeiten der Redakteure so klar und robust wie möglich zu gestalten.

Für dieses Beispiel nehmen wir an, dass wir ein Online-Corporate-Design-Handbuch erstellen.

  • Das Designhandbuch wird Seiten für verschiedene Designelemente, Farben, Schaltflächen, Schriftarten, Absätze usw. enthalten. 
  • Jede Seite kann aus mehreren (Unter-)Abschnitten mit detaillierten Beschreibungen und Richtlinien sowie mit Beispielen bestehen. 
  • Jeder Seitenabschnitt kann eine Überschrift, einen allgemeinen Beschreibungstext, Querverweislinks, verwandte Downloads und den Inhalt selbst haben, der aus verschiedenen Elementen und Inhaltstypen bestehen kann. 

Per Definition haben wir also

  • einige Seitenbereiche, die von einem Redakteur nur einmal gefüllt werden können (jedes Element sollte z.B. nur eine Überschrift, einen Beschreibungstext und einen Satz Links haben). 
  • und andere Bereiche, in denen der Redakteur möglicherweise mehrere andere Inhaltselemente hinzufügen muss.

Jede Seite im Corporate-Design-Handbuch kann mehrere solcher Abschnitte (Produkt-Teaser, News-Teaser, Event-Teaser, Kontakt-Teaser usw.) mit einer Mischung aus verschiedenen Inhaltstypen haben.

Bei dem unten gezeigten Beispieldesign handelt es sich um eine Seitenvorlage, die in Abschnitte unterteilt ist, die jeweils Unterstrukturen darstellen. Jeder Abschnitt kann eine Überschrift, einen Einleitungstext, verschiedene Inhaltselemente in der Hauptspalte und weitere optionale Inhalte in einer Seitenspalte haben. 

Wenn wir nur eine einzige Struktur wie diese hätten, würden wir mit einem regulären Backend-Layout beginnen. Da diese Struktur ein Inhaltsblock ist, der mehrfach auf derselben Seite platziert (und angepasst) werden kann, erstellen wir ein Containerelement. Wenn wir einen Container verwenden, haben wir ein Element mit einer eindeutigen uid, mit dem wir die seiteninternen Abschnittslinks von TYPO3 verwenden können, um seiteninterne Menüs oder seitenübergreifende Links zu dem jeweiligen Ankerpunkt zu erstellen.

Hier ist ein Design-Screenshot, der zeigt, was wir vorhaben:

Corporate Design Manual
Abbildung 1: Corporate Design Handbuch Seitenlayout

Das Container-Element konfigurieren

Hier ist das TCA für unser Beispiel-Container-Element:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
\TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(\B13\Container\Tca\Registry::class)->configureContainer(
(
new \B13\Container\Tca\ContainerConfiguration(
'cd-detail-section',
'CD Detail Section',
'Insert a detail section for Corporate Design Elements',
[
[
['name' => 'Main Column', 'colPos' => 201, 'allowed' => ['CType' => 'textmedia,cta,text,image,bullets,cd_text,footnotes']],
['name' => 'Sidebar Content', 'colPos' => 202, 'allowed' => ['CType' => 'text,sidebar-image']
]
]
)
)
->setIcon('EXT:site_cdmanual/Resources/Public/Icons/CD-Detail-Section.svg')
->setBackendTemplate('EXT:site_cdmanual/Resources/Private/Container/Templates/Cd-detail-section.html')
);

$GLOBALS['TCA']['tt_content']['types']['cd-detail-section']['showitem'] = '
--div--;LLL:EXT:core/Resources/Private/Language/Form/locallang_tabs.xlf:general,
--palette--;;general,
--palette--;;headers,
bodytext;LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:bodytext_formlabel,
--div--;LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:tabs.appearance,
--palette--;;frames,
--palette--;;appearanceLinks,
--div--;LLL:EXT:core/Resources/Private/Language/Form/locallang_tabs.xlf:language,
--palette--;;language,
--div--;LLL:EXT:core/Resources/Private/Language/Form/locallang_tabs.xlf:access,
--palette--;;hidden,
--palette--;;access,
--div--;LLL:EXT:core/Resources/Private/Language/Form/locallang_tabs.xlf:categories,
categories,
--div--;LLL:EXT:core/Resources/Private/Language/Form/locallang_tabs.xlf:notes,
rowDescription,
--div--;LLL:EXT:core/Resources/Private/Language/Form/locallang_tabs.xlf:extended,
'
;

$GLOBALS['TCA']['tt_content']['types']['cd-detail-section']['columnsOverrides']['bodytext']['config'] = [
'rows' => 5,
'enableRichtext' => true,
];
Abbildung 2: Containerkonfiguration in EXT:site_cdmanual/Configuration/TCA/Overrides/Cd-detail-section.php

Vergleicht man dies mit dem, was wir in Teil 2 mit dem einfachen 2-Spalten-Container gemacht haben, werden sofort zwei wesentliche Unterschiede deutlich:

  1. Die Container-Konfiguration selbst verwendet zusätzliche optionale Methoden, einschließlich der Einstellung eines Backend-Fluid-Templates und eines CType Icons.
  2. Wir fügen eine reguläre „showitem“-Konfiguration für den Container-CType hinzu.

Außerdem verwenden wir eine zusätzliche Spaltenkonfiguration, um die innerhalb eines bestimmten Inhaltsbereichs zulässigen Elementtypen einzuschränken. Dies ist nur möglich, wenn die Extension Content Defender von Nicole Cordes installiert ist. Diese praktische Extension ist eine unserer hausinternen Favoriten bei b13, und wir verwenden sie in allen unseren Projekten.

Hinzufügen einer „showitem“-Container-CType-Konfiguration

Der Prozess der Containerregistrierung legt eine Standardkonfiguration für die sichtbaren Felder eines Containerelements fest. Das Hinzufügen einer „showitem“-Konfiguration zur TCA-Konfiguration des Inhaltstyps ermöglicht es uns, die benötigten Felder zum Container selbst hinzuzufügen. In unserem Beispiel fügen wir eine Überschrift, ein Bodytextfeld für eine Einleitung und ein Layoutfeld hinzu. Wir arbeiten „core-nah“ mit einem Standard-CType für diese Container, so dass wir alle in der Tabelle tt_content verfügbaren Felder hinzufügen können.

Backend-Formular zur Bearbeitung unseres Container-Elements
Abbildung 3: Backend-Formular für unser Containerelement.

Dieses Beispiel enthält einen vollständigen Satz an Feldern. Man muss hier nicht alles hinzufügen, damit das funktioniert, aber man sollte das Language-Feld hinzufügen, wenn man an einer mehrsprachigen Website arbeitet, und die Palette „General“, die die Felder „CType“ und „colPos“ enthält.

Erstellen der Backend-Vorschau

Das Festlegen einer benutzerdefinierten Backend-Fluid-Vorlage ermöglicht es uns, unser eigenes Backend-Layout für das Seitenmodul zu definieren. Damit können wir den Redakteuren die Container-Inhaltsbereiche und die anderen verfügbaren Felder in unserem Containerelement anzeigen. Mit unserer benutzerdefinierten Fluid-Vorlage können wir diese Elementvorschauen auch frei gestalten.

Hier ist ein Beispiel-Fluid-Template für das Element, das wir gerade hinzugefügt haben:

1
2
3
4
5
6
7
<html data-namespace-typo3-fluid="true">
<a href="
{editLink.url -> f:format.raw()}" title="{editLink.title}">
{bodytext -> f:format.nl2br() -> f:format.stripTags()}
</a>
{tx_container_grid -> f:format.raw()}
</html>

Abbildung 4: Ein einfaches Fluid-Template für die Backend-Vorschau des Containerelements

Das bedeutet, dass das Fluid-Template, das zum Rendern der Backend-Vorschau unseres Containerelements verwendet wird, auf alle Standardfelder im tt_content-Datenbankeintrag zugreifen kann. Unsere Container-Erweiterung fügt eine weitere Variable mit dem Namen tx_container_grid hinzu. Diese Variable enthält das Container-Grid (in diesem Fall einschließlich der beiden Spalten, die im Container-Setup definiert wurden) als vollständigen HTML-Block, zusammen mit allen untergeordneten Elementen und Optionen zum Erstellen neuer Elemente. In diesem Beispiel fügen wir der Gesamtelementvorschau zusätzliche Vorschauinhalte (unser Einleitungstext-Feld) hinzu, bevor wir das Container-Grid in HTML rendern.

So sehen Redakteure unser Containerelement im TYPO3 Backend Seitenmodul:

Container Backend Vorschau
Abbildung 5: Elementvorschau für unseren Container mit benutzerdefiniertem Backend-Template

Mögliche weitere Konfiguration

Es gibt zusätzliche Methoden, die beim Registrieren eines Containers genutzt werden können:

  • setGridTemplate, um ein angepasstes Fluid-Template für ein Grid zu verwenden
  • setSaveAndCloseInNewContentElementWizard, um die „saveAndClose“ für den Assistenten für neue Inhaltselemente (für TYPO3 v10+) zu deaktivieren (default: true)
  • setRegisterInNewContentElementWizard, um die automatische Element-Registrierung im Assistenten für neue Inhaltselemente zu deaktivieren (default: true)
  • setGroup, um ein Container Element in eine spezifische Gruppe im CType-Dropdown und einen spezifischen Tab im New Content Element Wizard zu platzieren (default: container)

Grid Fluid Template

Das Standard-Grid-Template für die Vorschau des Backend-Seitenmoduls eines Containers funktioniert ähnlich wie die Verarbeitung von Backend-Layouts: Sie teilt den Elementbereich in Zeilen und Spalten auf der Grundlage der bei der Registrierung im TCA festgelegten Konfiguration auf. Dies dürfte für die meisten Elemente funktionieren — wie du in unserem Beispiel oben gesehen hast, kannst du in der Backend-Elementvorschau Inhalte aus anderen Feldern mit einer Mediengitteransicht kombinieren. Dennoch wird es hin und wieder dieses außergewöhnliche Szenario geben, bei dem das Standardlayout nicht ideal ist. Vielleicht möchtest du etwas CSS hinzufügen, um die Vorschau des Redakteurs abhängig von der Bildschirmgröße zu ändern, oder du hast ein komplexes Element, das „reguläre“ tt_content-Feldwerte mit bestimmten Inhaltsbereichen deines Containers kombiniert. 

Hier kommt der siebte Parameter ins Spiel: Für solche Fälle kannst du dein eigenes Grid-Template festlegen, um das Standard-Grid-Layout zu ändern. Die Standardvorlage befindet sich in EXT:container/Resources/Private/Templates/Grid.html. Diese einfache Vorlage (sie iteriert über Zeilen und Spalten) erzeugt die Ausgabe für die Backend-Grid-Ansicht.

Du kannst die Grid-Vorlage nach Belieben ändern, und z.B. einen Text zu einer der Spalten hinzufügen:

Benutzerdefinierte Backend-Elementvorschau für Container
Abbildung 6: Benutzerdefiniertes Backend-Grid-Template

Deaktivieren der Option „saveAndClose“

Die Container-Erweiterung nutzt das neue „saveAndClose“-Argument in TYPO3 v10 für den New Content Element Wizard (siehe Punkt 13 in 13 kleine Dinge, die wir an TYPO3 v10 lieben), um mehr über dieses kleine Juwel zu erfahren). Standardmäßig ist es auf „true“ gesetzt. Wenn ein neuer Container hinzugefügt wird, kann die setSaveAndCloseInNewContentElementWizard Methode verwendet werden, um dieses Verhalten zu deaktivieren.

Deaktivieren der automatische Aufnahme in den Assistenten für neue Inhaltselemente

Jedes erstellte Containerelement wird dem Assistenten für neue Inhaltselemente automatisch hinzugefügt, wobei die in der TCA-Registrierung angegebenen Konfigurationsdetails verwendet werden. Falls du dieses Verhalten ändern möchtest, z.B. um ein Containerelement auf ein bestimmtes Tab im Assistenten zu verschieben, die Elemente innerhalb des Tabs neu anzuordnen oder aus einem anderen Grund — benutze die Methode setRegisterInNewContentElementWizard, um dieses Verhalten zu deaktivieren. Der Container wird dem Assistenten für neue Inhaltselemente nicht automatisch hinzugefügt, so dass du dies in deiner PageTSConfig-Konfiguration selbst tun kannst.

Einen Container in eine andere Gruppe verschieben

Alle Container Elemente werden in einem Tab im New Content Element Wizard und im CType-Dropdown in einer Gruppe „Container“ gruppiert. Wenn Du diese Verhalten für ein spezifisches Element ändern möchstes, benutze die Methode setGroup, um das Element in einen anderen Tab/eine andere CType-Gruppe einzuordnen.

Willst du mehr? Möchtest du dich beteiligen?

In den drei Teilen dieser Serie über Flexible Container und Grids für TYPO3 stellten wir die grundlegenden Konzepte rund um Layout-„Container“ für TYPO3 vor, wenn man mehr als standardmäßig angebotene Core-Funktionen benötigt, wie unsere Container-Extension eine saubere „core-nahe“ Lösung bietet und lieferten einfache und komplexere Beispiele für die Implementierung von Containern in deinen Projekten. Nun, nachdem du sie alle gelesen hast, probiere es selbst aus!

Und was, wenn du einen Bug in Container gefunden hast? (Huch!) Oder eine fehlende Funktion benötigst? Haben wir noch etwas vergessen? Nimm Kontakt mit uns auf! Geh rüber zu GitHub, öffne einen Issue und erstell einen Pull-Request!

Vielen Dank im Voraus für dein kritisches Auge und deine Beiträge. Das alles hilft uns dabei, unser Lieblings-Open-Source-Projekt für alle besser zu machen.