Blog Kontakt

Komponentenbasierte Content-Architekturen ermöglichen im Vergleich zu seiten­basierten Ansätzen die einfache Wieder­verwendung von Oberflächen, verkürzen Entwicklungs­prozesse und steigern die Codequalität. Mit „Nested Blocks“ stellen wir Content Manager:innen und Entwickler:innen ein Sulu CMS Feature vor, das flexible Szenarien zur Inhalts­erstellung ermöglicht.

Vorteile von komponentenbasierten Content-Architekturen

Blöcke sind eine der populärsten Funktionen von Sulu. Sie ermöglichen es, verschiedene gruppierte Elemente wie Text, Bilder, Videos oder Formulare auf einer Seite anzupassen oder neu anzuordnen, ohne dabei den gesamten Inhalt der Seite ändern zu müssen. Einzelne Blöcke können zudem dupliziert, in andere Inhaltsseiten eingefügt oder per Drag & Drop sortiert werden, was diesen deutliche Vorteile gegenüber rein seitenbasierten, und damit oft sehr „starren“ Templates bietet.

Mit „Nested Blocks" ist es seit Sulu 2.1 zudem möglich, unabhängige Blöcke ineinander zu verschachteln, zu kombinieren und auf verschiedenen Seiten wiederzuverwenden. Mussten Entwickler:innen bisher für dynamische Inhalte den Umweg über Snippets gehen, können Blöcke nun aus der Administrationsoberfläche heraus hinzugefügt und in der Seitenvorschau angezeigt werden. Doch welche Vorteile versprechen „Nested Blocks“ darüber hinaus in der Praxis und wie fördern sie einen ganzheitlichen und progressiven Entwicklungsworkflow?

Um zunächst die strukturellen Unterschiede zwischen seitenbasierten Ansätzen und verschachtelten und wiederverwendbaren Blöcken zu verdeutlichen, hilft ein Beispiel aus der Praxis: Das Screendesign einer Kundin enthält allerlei UI-Elemente, die sich sowohl optisch als auch inhaltlich stark ähneln. Dazu gehören Sections mit wiederkehrenden Überschriften und Einleitungstexten, Vorschaulisten für Blogposts oder Slider, die entweder Medieninhalte oder benutzerdefinierte Entitäten wie Teammitglieder darstellen.

Bei einem klassischen seitenbasierten Ansatz würde für jede Seite aus dem Styleguide ein individueller Sulu-Seitentyp (sog. „Page Templates“) mit festen Feldern (sog. „Content Types“) angelegt werden. Jeder Seitentyp wird mit einem Twig-Template verknüpft und ausgegeben, wobei es schnell zu Duplikaten kommt: Obwohl jede Section auf der Start- und den Unterseiten die Eigenschaften „Überschrift“ oder „Beschreibungstext“ besitzt und sich eigentlich nur in der Form des dargestellten Mediums (z.B. Video / Bild / Person) unterscheidet, müssen sowohl die gemeinsamen als auch die inhaltsspezifischen Felder an mehreren Stellen im Code definiert werden. Soll nun in einem späteren Schritt die Labels der Felder geändert werden, ein neuer Galerietyp sowohl Bilder als auch Youtube-Videos darstellen können oder einzelne Felder auf einer anderen Seite erscheinen, muss erneut Hand angelegt werden. Dies verzögert die Bearbeitung von Inhalten für Content Manager:innen, führt zu zusätzlichem Aufwand und reproduziert Copy & Paste-basierte Entwicklungsmuster.

Sulu Entwickler:innen sind daher besser mit modularen Ansätzen wie „Nested Blocks“ beraten, welche die Umsetzung einer komponentengetriebenen Entwicklung unabhängig von der eigentlichen Zielseite ermöglichen. Die beiden behandelten Formen von Content-Architekturen lassen sich grob wie folgt gegenüberstellen:

 Seitenbasierte Content-ArchitekturModulare Content-Architektur
AnsatzTop-to-bottomBottom-to-top
ZielUmsetzung von vollständigen InhaltsseitenEigenständige, implementierungs-agnostische und wiederverwendbare Komponenten
Änderungs­aufwandHoch, da Effekte von Anpassungen auf gesamter Seite getestet werden müssenGering, da Komponenten isoliert entwickelt und ggf. in anderen Projekten wiederverwendet werden
Coding-GrundsatzWET (Write Everything Twice)DRY (Dont Repeat Yourself) & SOC (Separation of Concerns)
Template­strukturEin Template für jeden Seitentyp. Vererbungen und geteilte Eigenschaften von Elementen sind selten.Ein Template für jede Komponente. Vererebungen und geteilte Eigenschaften sind first-class citizens.

Abstraktion und Implementierung

Anstelle einer bloßen Umsetzung von (Unter-)Seiten auf Basis vorgegebener Screendesigns rückt die Aufgabe von Entwickler:innen zunehmend in die Bereitstellung eigenständiger Bibliotheken. Um diese in Inhaltstypen und modulare Templates zu überführen, sollte zunächst mit Hilfe des Styleguides ein Überblick über wiederkehrende UI-Muster und User-Flows gewonnen werden. Hieraus lassen sich modulare Komponenten ableiten, welche später – in der Regel durch die Content-Manager:innen selbst – kombiniert und verschachtelt werden.

Ausgehend von einem „from-bottom-to-top“-Ansatz sind Blöcke dabei immer implementierungsagnostisch zueinander: Wie eine Liste von Blogposts unter-, über-, nebeneinander, oder in einem modalen Fenster dargestellt wird, ist zunächst einmal die Aufgabe des darüber liegenden Elements, oft der Seite selbst. Bei der Idenifizierung von Abständen nach innen und außen sollten die unterschiedlichen Muster zwischen den einzelnen Viewports und Geräteklassen berücksichtigt werden. Auch wenn die finale Umsetzung der daraus resultierenden Inhaltsstrukturen und Komponenten immer projektabhängig ist, empfiehlt sich eine Vorgehensweise, die den vier Schritten „Discover – Abstract – Implement & Document – Integrate“ folgt:

1. Bestimme zunächst die Grenzen und Schnittmengen von UI-Elementen: Wo beschreiben diese ein isoliertes Element mit dynamischen Eigenschaften (z.B. ein Button mit unterschiedlichen inneren Abständen oder Zuständen), und wo liegen klar erkennbare, global wiederkehrende Muster zwischen den verschiedenen Elementen (etwa Schatten oder Farben, welche sowohl für Hintergründe als auch Texte genutzt werden)? Diese können idealerweise als „Design Token“ definiert werden, wenn ein utility-first CSS-Toolkits wie Tailwind verwendet wird, oder in Form von globalen Variablen oder Mixins in SASS wiederverwendet werden, um duplizierte Styles zwischen einzelnen Komponenten zu vermeiden.

2. Abstrahiere einzelne Elemente in zusammenhängende Komponenten, die einen Block darstellen. Dies könnte z.B. eine Section mit Titel, Beschreibungstext und einem Bild sein, das optional hochgeladen werden und seitlich neben dem Inhalt positioniert werden kann. Identifiziere dabei iterativ die Abhängigkeiten der Komponenten zueinander: Reicht es, das Bild als fixes Feld vom Typ „Media selection“ anzulegen oder könnte es sich lohnen, hier einen dynamischem „Block im Block“ bereitzustellen, um sehr ähnliche Darstellungen von Unterblöcken zwischen Seiten zu ermöglichen? Ist dies der Fall, lässt sich weiter evaluieren, ob an dieser Stelle nur einer oder mehrere bestimmte Blöcke auswählbar sein sollten, oder ob perspektivisch sogar die Auswahl aller global zur Verfügung stehenden Blöcke sinnvolle Szenarios ermöglichen (bspw. Produktfeature-Blöcke, Galerien oder Slider)?

3. Implementiere Blöcke ganzheitlich. Dazu sollte jede Komponente einen eindeutigen, generischen Namen erhalten, der im Wording vom Block, Twig-Template, der BEM-Klassen oder verbundener Stimulus-Controller/WebComponents auftaucht. Insbesondere Anfänger:innen laufen oft Gefahr, aufgrund des zugrunde liegenden Styleguides zu spezifische Namen für Komponenten zu wählen, was deren Integration in andere Umgebungen zu späterer Zeit erschwert - z.B. „staff-member-gallery“ statt „gallery“ oder „faq-list“ anstelle eines einfachen „accordion“. Generell ist es sinnvoll, weniger die dargestellten Inhalte, als die eigentliche Funktion der Komponente zu betrachten, um diese später an anderer Stelle wiederverwenden zu können oder im Sinne einer progressiven Entwicklung für weitere Anwendungsfälle zu erweitern.

4. Integriere verschachtelte Blöcke miteinander: Besteht ein Block aus einem oder mehreren Unterblöcken, so muss deren Integration in den übergeordneten Block anhand der zu Beginn identifizierten Abstandsregeln überprüft werden. Eine Anforderung aus dem Styleguide könnte z.B. sein, dass Medieninhalte wie Bilder oder Videos in einer Vorschaukarte immer die volle Breite einnehmen, während Überschriften und Fließtext immer einen Abstand nach innen und zueinander einhalten müssen. Es ist ebenfalls möglich, dass verschachtelte Blöcke über eine am übergeordneten Block einstellbaren Auswahlliste sowohl horizontal als auch vertikal verlaufen können, was wiederum neue Abstandsregeln erfordert. Um eine unüberschaubare Anzahl von Variationen zu vermeiden, können über die Eigenschaften „minOccurs“ und „maxOccurs“ eines Blocks die Anzahl der Unterblöcke genau festgelegt, und über das Element „types“ die verfügbaren Unterblöcke eingeschränkt werden. Dies möchten wir uns nun genauer anschauen.

Hands-on: Entwicklung von „Nested Blocks“ in Sulu CMS

Im Folgenden geben wir einen exemplarischen Einblick in die Entwicklung verschachtelter Blöcke mit Sulu und stellen Tipps vor, welche die Wiederverwendung von Blöcken und globalen Blockeigenschaften vereinfachen. Für einen vollständigen Überblick über gängige Best Practices empfiehlt sich ein Blick in die offizielle Content Blocks Dokumentation sowie in den "How to set up a block" Guide des Sulu Teams.

1. Anlegen von (verschachtelten) Blöcken

Innerhalb eines XML-Seitentemplates legen wir zunächst eine Section „content“ mit dem Inhaltstyp „Block“ als einzige Property an:

<?xml version="1.0" encoding="UTF-8"?>
<section name="content">
   <meta>
      <title lang="en">Content blocks</title>
      <title lang="de">Inhaltsblöcke</title>
   </meta>
   <properties>
      <block name="blocks">
         <types>
            <!-- Jeder hier definierte Unterblock („type“) kann via Dropdown ausgewählt werden -->
         </types>
      </block>
   </properties>
</section>

Neben dem Namen können am Block auch die Eigenschaften „minOccurs“ und „maxOccurs“ definiert werden, um eine minimale bzw. maximale Anzahl von Unterblöcken zu definieren (ein Slider ohne Elemente oder mit mehr als vier Slides wäre z.B. aus UX-Sicht eher fragwürdig). Sollen mehrere Unterblöcke auswählbar sein, kann der initial anzuzeigende Block anhand seines Maschinennamens über die Eigenschaft „default-type“ konfiguriert werden. Anschließend werden die eigentlichen Unterblöcke angelegt, welche die im Styleguide definierte Conent-Struktur – d.h. Felder oder weitere Unterblöcke - implementieren. Nachfolgend ein Beispiel für diese Szenarien anhand eines einfachen „Hero“-Blocks und eines verschachtelten „Slider“-Blocks:

<?xml version="1.0" encoding="UTF-8"?>
<!-- Innerhalb der <types> aus obigem Beispiel: -->
<types>
   <type name="hero">
      <meta>
         <title lang="de">Hero mit Bild und Überschrift</title>
         <title lang="en">Hero with image and headline</title>
      </meta>
      <properties>
         <property name="images" type="single_media_selection">
            <meta>
               <title lang="de">Bild</title>
               <title lang="en">Image</title>
            </meta>
         </property>
         <property name="headline" type="text_line">
            <meta>
               <title lang="de">Überschrift</title>
               <title lang="en">Headline</title>
            </meta>
         </property>
      </properties>
   </type>
   <type name="slider">
      <meta>
         <title lang="en">Slider</title>
         <title lang="de">Slider</title>
      </meta>
      <properties>
         <block name="blocks" minOccurs="1">
            <params>
               <param name="add_button_text">
                  <meta>
                     <title lang="de">Slide hinzufügen</title>
                     <title lang="en">Add slide</title>
                  </meta>
               </param>
            </params>
            <types>
               <!-- „type“ mit Feldern, etwa Bild, Link und Titel -->
            </types>
         </block>
      </properties>
   </type>
</types>

2. Darstellung von Blöcken in Twig

Das mit dem Sulu-Seitentemplate verknüpfte Twig-Template bindet über Twigs „include“-Anweisung das neu zu erstellende Template includes/blocks.html.twig ein, welches wiederum über den folgenden Inhalt die eigentlichen Block-Templates aus dem „includes/blocks“ Ordner einbindet:

{% if content.blocks|default([]) %}
    {% for block in content.blocks %}
    <section class="block block--{{ block.type }}">
    {% include 'includes/blocks/' ~ block.type ~ '.html.twig' with {
        content: block,
         view: view.blocks[loop.index0],
     } %} 
    </section>
    {% endfor %} 
{% endif %}

In diesem Beispiel wird die BEM-Methodik zur Benennung von Blöcken verwendet (etwa .block.block—slider). Hierdurch können auf komfortable Art und Weise sowohl globale auch auch Block-spezifische Styles im (S)CSS-Code definiert werden.

3. Properties in XML-Seitentemplates wiederverwenden

Häufig werden sehr ähnliche Eigenschaften wie der Titel oder die Hintergrundfarbe einer Section von mehreren Blöcken verwendet. Um im Sinne des DRY-Prinzips Doppelungen in der Seitenlogik und -struktur zu vermeiden, können diese Eigenschaften über den XInclude-Mechanismus in ein XML-Template ausgelagert und an anderer Stelle wieder importiert werden. Dies kann als Teil einer neu zu erstellenden section_base_properties.xml etwa so aussehen:

<?xml version="1.0" encoding="UTF-8"?>
<properties xmlns="http://schemas.sulu.io/template/template" xmlns:xi="http://www.w3.org/2001/XInclude" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://schemas.sulu.io/template/template http://schemas.sulu.io/template/template-1.1.xsd">
   <property name="background_color" type="single_select">
      <meta>
         <title lang="en">Background color</title>
         <title lang="de">Hintergrundfarbe</title>
      </meta>
      <params>
         <param name="default_value" value="white" />
         <param name="values" type="collection">
            <param name="white">
               <meta>
                  <title lang="en">White</title>
                  <title lang="de">Weiss</title>
               </meta>
            </param>
            <param name="grey">
               <meta>
                  <title lang="en">Grey</title>
                  <title lang="de">Grau</title>
               </meta>
            </param>
         </param>
      </params>
   </property>
   <!-- etc. -->
</properties>

Dieses Fragment kann nun via xi:include in einem Seitentemplate importiert werden:

<?xml version="1.0" encoding="UTF-8"?>
<template xmlns="http://schemas.sulu.io/template/template" xmlns:xi="http://www.w3.org/2001/XInclude" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://schemas.sulu.io/template/template http://schemas.sulu.io/template/template-1.0.xsd">
   <!--- ... -->
   <properties>
      <xi:include href="../includes/section_base_properties.xml" xpointer="xmlns(sulu=http://schemas.sulu.io/template/template)xpointer(/sulu:properties/sulu:block/sulu:types/sulu:type)" />
   </properties>
   <!--- ... -->
</template>

Zu beachten ist hierbei das korrekte Setzen der Property xmlns:xi im Template-Tag.

4. Blöcke in XML-Templates auslagern und in blocks.xml zusammenfassen

Die Verwendung von xi:include ermöglicht es darüber hinaus, Blöcke und Sammlungen von Blöcken in einzelne XML-Templates auszulagern. Genau wie in dem zuvor erstellten blocks.html.twig Twig-Template kann eine in allen Seitentemplates importierte blocks.xml die Wiederverwendung von Blöcken auf allen Unterseiten sicherstellen oder als Basis für weitere Variationen von Blöcken dienen. Änderungen an der Konfiguration eines Blocks wirken sich somit auf alle Seiten aus, auf denen dieser Block implementiert ist.

Fazit

Mithilfe von verschachtelten Blöcken in Sulu können modulare bzw. komponentenbasierte UI-Ansätze in eine progressiv erweiterbare Content-Architektur überführt und stringent Twig und mittels CSS-Naming-Conventions wiederverwendet werden. Dies gibt Content Manager:innen erweiterte Gestaltungsmöglichkeiten von Inhalten, ohne auf starr vordefinierte Seitentemplates angewiesen zu sein. Die Auslagerung wiederkehrender Blockeigenschaften in eigenständige XML-Templates erleichtert darüber hinaus die Komposition neuer Inhaltstypen und reduziert Redundanzen in der Codebasis.

Sie planen eine Neuentwicklung oder einen Relaunch Ihrer Website? Wir freuen uns über Ihre Nachricht.

Diese Artikel könnten Sie auch interessieren

Interesse geweckt?

Alle Artikel anzeigen