Hyvä Page-Builder-Content-Types entwickeln und stylen
AI generated
Hyvä
phtml
Hyvä · Page Builder · Content Types · Magento 2
Hyvä Page-Builder-Content-Types bauen und stylen
vom Master-Format bis zur Alpine.js-Komponente

Eigene Hyvä Page-Builder-Content-Types entstehen nicht durch Knockout-Widgets, sondern durch serverseitiges phtml-Rendering mit Tailwind-Klassen und gezielter Alpine.js-Interaktivität. Dieser Guide zeigt Registrierung, Rendering-Architektur und Performance-Patterns anhand echter Code-Beispiele.

18 Min. Lesezeit content_type.xml · appearance.xml · Alpine.js · Tailwind CSS Magento 2.4.x · Hyvä 1.3+ · Page Builder

1. Warum Page Builder in Hyvä eine Sonderrolle einnimmt

In Luma wird Page-Builder-Content clientseitig über Knockout.js-Widgets gerendert: Jeder Content-Type bringt eine eigene RequireJS-Komponente mit, die im Browser das gespeicherte Master-Format in DOM-Elemente übersetzt. Das bedeutet zusätzliche JavaScript-Bundles, Knockout-Bindings und eine Rendering-Kette, die genau den Technologien widerspricht, die Hyvä bewusst vermeidet. Hyvä Page-Builder-Content-Types lösen dieses Problem grundlegend anders: Das Kompatibilitätsmodul hyva-themes/magento2-page-builder ersetzt die komplette clientseitige Rendering-Pipeline durch serverseitiges PHP-Rendering.

Für Redakteure ändert sich im Admin-Editor nichts, sie arbeiten weiterhin mit der gewohnten Drag-and-Drop-Oberfläche von Magento_PageBuilder. Der entscheidende Unterschied liegt im Frontend: Statt Knockout-Komponenten zu hydrieren, liest Hyvä den gespeicherten Content-Baum serverseitig ein und rendert jeden Knoten über ein eigenes phtml-Template. Damit werden Hyvä Page-Builder-Content-Types zu vollwertigen, CSP-konformen Bestandteilen des Themes, ohne dass zusätzliches Bundle-JavaScript oder jQuery-Abhängigkeiten geladen werden müssen.

2. Architektur: Master-Format-Renderer statt Knockout-Widget-Rendering

Page Builder speichert Inhalte im sogenannten Master-Format, einer HTML-Struktur mit data-content-type-Attributen, verschachtelten Containern und Style-Informationen. In Luma übernimmt ein clientseitiger Konverter diese Struktur und bindet für jeden Knoten eine Knockout-Komponente. Bei Hyvä Page-Builder-Content-Types übernimmt stattdessen ein PHP-Renderer den gesamten Baum: Er läuft den Structure-Tree einmal serverseitig durch, löst für jeden Knotentyp das passende Template auf und rendert das Ergebnis direkt in die Seite.

Diese Architekturentscheidung hat spürbare Konsequenzen. Es gibt keine Laufzeit-Hydrierung im Browser, keine zusätzlichen Netzwerk-Requests für Widget-Definitionen und keinen Layout-Shift durch nachträglich eingehängte Komponenten. Die Zuordnung von Content-Type-Name zu Template erfolgt deklarativ über content_type.xml, wodurch Hyvä Page-Builder-Content-Types genauso wie normale Block-Templates in den Hyvä-Rendering-Zyklus eingebettet sind und sich mit Tailwind-Klassen stylen lassen wie jedes andere Theme-Fragment.

3. Einen eigenen Content-Type registrieren

Ein neuer Content-Type benötigt mindestens zwei Deklarationsdateien: content_type.xml definiert Name, Label, Icon und die verfügbaren Appearances, während appearance.xml die Formularfelder festlegt, die Redakteure im Page-Builder-Editor ausfüllen können. Beide Dateien folgen dem gleichen deklarativen Muster wie andere Magento-Konfigurationsdateien und werden pro Modul unter etc/pagebuilder/ abgelegt.


<!-- app/code/Mironsoft/PageBuilder/etc/pagebuilder/content_type.xml -->
<?xml version="1.0"?>
<content_types xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:noNamespaceSchemaLocation="urn:magento:module:Hyva_PageBuilder:etc/pagebuilder/content_type.xsd">
    <type name="feature-callout" label="Feature Callout" icon="icon-feature-callout" component="Magento_PageBuilder/js/content-type">
        <appearances>
            <appearance name="default" default="true"
                template="Mironsoft_PageBuilder::content-type/feature-callout/default.phtml"/>
            <appearance name="highlighted"
                template="Mironsoft_PageBuilder::content-type/feature-callout/highlighted.phtml"/>
        </appearances>
    </type>
</content_types>

<!-- app/code/Mironsoft/PageBuilder/etc/pagebuilder/feature-callout/appearance.xml -->
<?xml version="1.0"?>
<appearances xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_PageBuilder:etc/appearance.xsd">
    <appearance name="default">
        <elements>
            <element name="headline">
                <converter component="Magento_PageBuilder/js/content-type/text/converter" property="headline"/>
            </element>
            <element name="text">
                <converter component="Magento_PageBuilder/js/content-type/text/converter" property="text"/>
            </element>
            <element name="background_color">
                <converter component="Magento_PageBuilder/js/converter/style-attribute" property="background-color"/>
            </element>
        </elements>
    </appearance>
</appearances>

Der template-Attributwert in content_type.xml ist die entscheidende Hyvä-spezifische Ergänzung: Er verweist auf das phtml-Template, das der PHP-Renderer für diese Appearance verwendet. Ohne diesen Eintrag fällt Hyvä auf ein generisches Fallback-Template zurück, das die Formularfelder unformatiert ausgibt. Wer Hyvä Page-Builder-Content-Types sauber registriert, achtet außerdem auf einen eindeutigen Modul-Namespace im name-Attribut, damit keine Kollisionen mit Core-Content-Types wie banner oder row entstehen.

4. Rendering-Template im Hyvä-Stil bauen

Das eigentliche Rendering-Template ist ein gewöhnliches phtml-Template, das die im Master-Format hinterlegten Feldwerte als Array erhält. Der wichtigste Unterschied zu einem generischen Page-Builder-Theme: Statt der Core-CSS-Klassen wie pagebuilder-content-type oder Bootstrap-Grid-Klassen verwenden Hyvä Page-Builder-Content-Types ausschließlich Tailwind-Utility-Klassen, die zum bestehenden Design-System des Themes passen.


<?php
/** @var \Magento\Framework\View\Element\Template $block */
/** @var array $data */
// $data is provided by the Hyvä PageBuilder renderer with all master-format field values
$data = $block->getData('content_type_data') ?? [];
$headline = (string) ($data['headline'] ?? '');
$text = (string) ($data['text'] ?? '');
$backgroundColor = (string) ($data['background_color'] ?? '#0f172a');
?>
<div class="not-prose rounded-2xl p-6 sm:p-8 my-6" style="background-color: <?= $block->escapeHtmlAttr($backgroundColor) ?>;">
    <?php if ($headline !== ''): ?>
    <p class="text-white text-xl font-bold mb-2"><?= $block->escapeHtml($headline) ?></p>
    <?php endif; ?>
    <?php if ($text !== ''): ?>
    <div class="text-white text-sm prose prose-invert max-w-none">
        <?= /* @noEscape */ $text ?>
    </div>
    <?php endif; ?>
</div>

Bewährt hat sich außerdem, Abstands- und Typografie-Skalen aus der Tailwind-Konfiguration wiederzuverwenden statt eigene Pixelwerte zu definieren. So bleiben Hyvä Page-Builder-Content-Types visuell konsistent mit dem restlichen Theme, auch wenn Redakteure Inhalte frei zusammenstellen. HTML-Felder wie text müssen bewusst ungeschützt ausgegeben werden, da sie bereits redaktionell erzeugtes, formatiertes HTML enthalten, während einfache String-Felder immer über escapeHtml laufen.

5. Alpine.js-Interaktivität in eigenen Content-Types einbauen

Sobald ein Content-Type mehr als statisches Markup braucht, etwa Tabs oder ein Akkordeon, kommt Alpine.js ins Spiel, das in Hyvä ohnehin global geladen ist. Kein zusätzliches Bundle, kein separates RequireJS-Modul: Die Interaktivität wird direkt als x-data-Attribut im Template deklariert, wodurch Hyvä Page-Builder-Content-Types interaktiv bleiben, ohne die CSP-Konfiguration zu verletzen.


<?php
/** @var \Mironsoft\PageBuilder\Block\ContentType\Tabs $block */
// Tabs are stored as repeatable child elements in the master format
$tabs = $block->getTabs(); // array<int, array{label: string, html: string}>
?>
<div class="not-prose my-6" x-data="{ active: 0 }">
    <div class="flex flex-wrap gap-2 border-b border-slate-200 mb-4">
        <?php foreach ($tabs as $index => $tab): ?>
        <button
            type="button"
            @click="active = <?= (int) $index ?>"
            :class="active === <?= (int) $index ?> ? 'border-orange-600 text-orange-700' : 'border-transparent text-slate-500'"
            class="px-4 py-2 border-b-2 font-semibold text-sm transition-colors"
        ><?= $block->escapeHtml($tab['label']) ?></button>
        <?php endforeach; ?>
    </div>
    <?php foreach ($tabs as $index => $tab): ?>
    <div x-show="active === <?= (int) $index ?>" x-cloak class="prose prose-sm max-w-none">
        <?= /* @noEscape */ $tab['html'] ?>
    </div>
    <?php endforeach; ?>
</div>

Wichtig ist, den aktiven Tab-Index nicht per Mustache-Ausdruck, sondern über x-show und Alpine-Bindings zu steuern, da Page-Builder-Templates serverseitig vorgerendert werden und keine Template-Interpolation zur Laufzeit stattfindet. Für Text-Ausgaben innerhalb von Alpine-Komponenten gilt dieselbe Regel wie im restlichen Theme: x-text statt geschweifter Klammern, damit auch bei deaktiviertem JavaScript kein unaufgelöster Platzhalter sichtbar wird. So bleiben Hyvä Page-Builder-Content-Types mit Alpine-Logik wartbar und CSP-sicher zugleich.

6. Master-Format-Parser und Platzhalter-Konvertierung verstehen

Page Builder legt Formatierungsinformationen wie Textfarbe, Ausrichtung oder Innenabstand als HTML-kodiertes data-pb-style-Attribut ab. Beim Rendern von Hyvä Page-Builder-Content-Types muss dieses Attribut zunächst dekodiert, dann in eine Liste von Key-Value-Paaren zerlegt und schließlich auf erlaubte Tailwind-Klassen gemappt werden. Wer diesen Schritt überspringt und Style-Attribute unkontrolliert in Inline-Styles kopiert, öffnet die Tür für CSP-Verstöße und inkonsistentes Styling.


<?php

declare(strict_types=1);

namespace Mironsoft\PageBuilder\Model\MasterFormat;

/**
 * Decodes Page Builder master-format style attributes into whitelisted Tailwind utility classes.
 */
class StyleAttributeResolver
{
    /** @var string[] */
    private const ALLOWED_KEYS = ['text-align', 'background-color', 'padding'];

    /**
     * Convert a raw data-pb-style attribute string into Tailwind classes.
     *
     * @param string $rawStyle
     * @return string
     */
    public function toTailwindClasses(string $rawStyle): string
    {
        // Master format stores style as HTML-encoded "key: value;" pairs
        $decoded = html_entity_decode($rawStyle, ENT_QUOTES | ENT_HTML5);
        $pairs = array_filter(array_map('trim', explode(';', $decoded)));
        $classes = [];

        foreach ($pairs as $pair) {
            [$key, $value] = array_pad(explode(':', $pair, 2), 2, '');
            $key = trim($key);
            if (!in_array($key, self::ALLOWED_KEYS, true)) {
                continue;
            }
            $classes[] = $this->mapToTailwind($key, trim($value));
        }

        return implode(' ', array_filter($classes));
    }

    /**
     * Map a single CSS key/value pair to its Tailwind utility equivalent.
     *
     * @param string $key
     * @param string $value
     * @return string
     */
    private function mapToTailwind(string $key, string $value): string
    {
        return match ($key) {
            'text-align' => 'text-' . $value,
            'padding' => 'p-4',
            default => '',
        };
    }
}

Typische Fallstricke entstehen beim Kopieren von Inhalten aus Word oder Google Docs in den Page-Builder-Editor: Sonderzeichen werden doppelt HTML-kodiert, und geschachtelte Content-Types können ihrerseits kodierte Anführungszeichen enthalten, die beim ersten Decode-Durchlauf nicht vollständig aufgelöst werden. Für robuste Hyvä Page-Builder-Content-Types empfiehlt sich daher, den Decode-Schritt einmal zentral im Renderer auszuführen statt in jedem einzelnen Template erneut.

7. Konsistenz zwischen Admin-Editor-Preview und Frontend-Rendering sicherstellen

Der Page-Builder-Editor im Admin nutzt weiterhin ein eigenes, Knockout-basiertes Preview-Template, unabhängig davon, dass das Frontend über Hyvä phtml-basiert rendert. Weichen Preview- und Frontend-Template optisch voneinander ab, verlieren Redakteure das Vertrauen in die What-you-see-is-what-you-get-Vorschau, und Korrekturschleifen zwischen Redaktion und Entwicklung nehmen zu.

In der Praxis bewährt sich, gemeinsame Werte wie Abstände, Schriftgrößen und Farbpaletten in einer zentralen Konfiguration zu pflegen und sowohl im Knockout-Preview-Template als auch im phtml-Frontend-Template zu referenzieren, statt sie zweimal unabhängig zu pflegen. So bleibt die Vorschau für Hyvä Page-Builder-Content-Types auch nach Design-Anpassungen synchron mit dem tatsächlichen Rendering im Shop.

Als Testroutine empfiehlt sich ein regelmäßiger visueller Vergleich zwischen Admin-Preview-iFrame und der veröffentlichten Seite, idealerweise automatisiert über Screenshot-Diffs in der CI-Pipeline. Das deckt Abweichungen auf, bevor Redakteure sie in der Produktion bemerken.

8. Performance eigener Content-Types

Da Hyvä Page-Builder-Content-Types ohnehin ohne zusätzliches Bundle-JavaScript auskommen, verschiebt sich die Performance-Optimierung auf Bilder und schwergewichtige Komponenten wie Slider. Bilder innerhalb eines Content-Types sollten grundsätzlich mit loading="lazy" ausgestattet werden, während Slider-Content-Types zusätzlich von einem Intersection-Observer profitieren, der Bildquellen erst beim Erreichen des Viewports nachlädt.


// Lazy-load slider images inside Page Builder content types only once visible
document.addEventListener('DOMContentLoaded', () => {
    const sliders = document.querySelectorAll('[data-pagebuilder-slider]');

    const observer = new IntersectionObserver((entries, obs) => {
        entries.forEach((entry) => {
            if (!entry.isIntersecting) {
                return;
            }
            const slider = entry.target;
            slider.querySelectorAll('img[data-src]').forEach((img) => {
                img.src = img.dataset.src;
                img.removeAttribute('data-src');
            });
            obs.unobserve(slider);
        });
    }, { rootMargin: '200px 0px' });

    sliders.forEach((slider) => observer.observe(slider));
});

Da Hyvä kein RequireJS ausliefert, entfällt zusätzlich der Overhead durch Modul-Definitionen und asynchrones Laden von AMD-Abhängigkeiten, die in Luma für jeden Slider-Content-Type nötig wären. In der Praxis senkt dieses Vorgehen den Largest Contentful Paint spürbar, weil Hyvä Page-Builder-Content-Types erst dann Bildlast erzeugen, wenn Besucher tatsächlich scrollen.

9. Migration bestehender Luma-Page-Builder-Inhalte auf Hyvä-Rendering

Der große Vorteil bei der Migration: Das im Master-Format gespeicherte HTML selbst ändert sich beim Wechsel von Luma zu Hyvä nicht, da es unabhängig vom Rendering-Layer in der Datenbank liegt. Der Umstieg auf Hyvä Page-Builder-Content-Types betrifft ausschließlich die Rendering-Schicht im Frontend, nicht die gespeicherten Inhalte selbst.

Breaking Changes entstehen typischerweise bei Content-Types, die in Luma auf jQuery-UI-Plugins oder Drittanbieter-Slider-Bibliotheken setzen, für die es noch kein Hyvä-Template gibt. Fehlt die Zuordnung in content_type.xml, rendert Hyvä ein leeres oder generisches Fallback statt des erwarteten Inhalts, was im schlimmsten Fall erst bei einer Stichprobe auffällt.

Als Teststrategie empfiehlt sich, vor dem Theme-Wechsel alle im CMS und in Kategorien verwendeten Content-Type-Appearances systematisch aufzulisten und gegen die vorhandenen Hyvä-Templates abzugleichen. Erst wenn für jede eingesetzte Appearance ein passendes phtml-Template existiert, lässt sich sicher sagen, dass Hyvä Page-Builder-Content-Types die komplette bestehende Content-Bibliothek abdecken.

Viele Teams unterschätzen, wie unterschiedlich Content-Type-Rendering je nach gewähltem Ansatz ausfällt. Die folgende Übersicht zeigt gängige Stolperfallen bei der Entwicklung eigener Hyvä Page-Builder-Content-Types im direkten Vergleich zum empfohlenen Pattern.

Aufgabe Unsicher / Ineffizient Empfohlenes Pattern Vorteil
Frontend-Rendering Generische Page-Builder-CSS-Klassen Eigenes phtml-Template mit Tailwind-Klassen Konsistentes Design-System, kein CSS-Bloat
Interaktivität Zusätzliches Bundle-JavaScript / Knockout-Widget Alpine.js x-data direkt im Template Kein zusätzliches Bundle, CSP-konform
Bilder im Content-Type Alle Bilder eager laden loading="lazy" plus Intersection Observer Bessere LCP-Werte, weniger Datenvolumen
Admin-Preview Preview-Template weicht vom Frontend ab Gemeinsame Design-Tokens für Preview und Frontend Konsistentes WYSIWYG für Redakteure
Content-Type-Registrierung Core-Templates direkt überschreiben Eigene content_type.xml mit eigenem Namespace Update-sicher, keine Core-Konflikte
Style-Attribute Inline-Styles unkontrolliert übernehmen Style-Attribute validieren und auf Tailwind mappen Kein CSS-Chaos, CSP-sauber

Mironsoft

Hyvä-Frontend-Entwicklung und Page-Builder-Integration für Magento 2

Eigene Page-Builder-Content-Types für euer Hyvä-Theme?

Wir registrieren, rendern und stylen eigene Hyvä Page-Builder-Content-Types, migrieren bestehende Luma-Inhalte und sorgen für performantes, CSP-konformes Rendering ohne zusätzliches Bundle-JavaScript.

Content-Type-Entwicklung

Eigene Content-Types mit content_type.xml, phtml-Templates und Alpine.js registrieren

Page-Builder-Migration

Bestehende Luma-Inhalte analysieren und auf Hyvä-Rendering überführen

Hyvä-Frontend-Design

Tailwind-basiertes Styling und Performance-Optimierung für Content-Bausteine

10. Zusammenfassung

Eigene Hyvä Page-Builder-Content-Types lösen ein grundlegendes Architekturproblem: Sie ersetzen die clientseitige Knockout-Rendering-Kette aus Luma durch serverseitiges phtml-Rendering, das ohne zusätzliches Bundle-JavaScript auskommt und sich mit Tailwind-Klassen konsistent stylen lässt. Die Registrierung erfolgt deklarativ über content_type.xml und appearance.xml, das eigentliche Rendering übernimmt ein gewöhnliches phtml-Template mit escapten Feldwerten.

Interaktivität kommt über Alpine.js hinzu, das in Hyvä ohnehin global verfügbar ist, während Performance-Optimierungen sich vor allem auf Lazy Loading von Bildern und Slidern konzentrieren. Das Master-Format selbst bleibt beim Wechsel von Luma zu Hyvä unverändert in der Datenbank, weshalb eine Migration in erster Linie die Rendering-Schicht betrifft, nicht die gespeicherten Inhalte.

Wer Hyvä Page-Builder-Content-Types von Anfang an konsequent nach diesen Patterns aufbaut, spart sich spätere Refactorings: Preview- und Frontend-Templates bleiben synchron, Style-Attribute werden kontrolliert statt roh übernommen, und jeder neue Content-Type fügt sich nahtlos in das bestehende Design-System des Themes ein.

Hyvä Page-Builder-Content-Types: Das Wichtigste auf einen Blick

Content-Type-Registrierung

content_type.xml und appearance.xml deklarieren Name, Appearances und Formularfelder, das template-Attribut verweist auf das phtml-Rendering-Template.

Master-Format-Rendering

Ein PHP-Renderer läuft den Structure-Tree serverseitig durch, statt Knockout-Widgets im Browser zu hydrieren. Style-Attribute werden kontrolliert dekodiert und gemappt.

Alpine.js-Interaktivität

Tabs, Akkordeons und ähnliche Interaktionen laufen über x-data, x-show und x-text, ohne zusätzliches Bundle-JavaScript zu laden.

Performance & Migration

Lazy Loading für Bilder und Slider, gemeinsame Design-Tokens für Preview und Frontend, systematischer Appearance-Abgleich vor dem Theme-Wechsel.

11. FAQ: Hyvä Page-Builder-Content-Types

1Was sind Hyvä Page-Builder-Content-Types genau?
Page-Builder-Bausteine, deren Frontend-Rendering serverseitig über phtml-Templates statt über Knockout-Widgets erfolgt. Editor und Registrierung bleiben zu Magento_PageBuilder identisch.
2Warum rendert Hyvä Page Builder anders als Luma?
Luma bindet Knockout-Komponenten per RequireJS ein. Hyvä verzichtet auf Knockout und jQuery, ein PHP-Renderer übernimmt die komplette Umsetzung des Master-Formats.
3Wie registriere ich einen eigenen Content-Type?
content_type.xml definiert Name und Appearances, appearance.xml die Formularfelder. Das template-Attribut verweist zusätzlich auf das Hyvä-phtml-Template.
4Welche Dateien braucht ein neuer Content-Type?
Mindestens content_type.xml, eine appearance.xml pro Appearance und ein phtml-Template pro Appearance. Optional eine Block- oder ViewModel-Klasse.
5Wie baue ich Alpine.js-Interaktivität ein?
x-data direkt im phtml-Template deklarieren, Zustand über x-show, x-bind und x-text steuern. Alpine ist in Hyvä global geladen, kein zusätzliches Bundle nötig.
6Was ist das Master-Format?
Die HTML-Struktur mit data-content-type- und data-pb-style-Attributen, in der Page Builder Inhalte speichert. Unabhängig vom Rendering-Layer, bleibt bei einem Theme-Wechsel unverändert.
7Wie halte ich Preview und Frontend synchron?
Gemeinsame Design-Tokens für Abstände, Schriftgrößen und Farben in Preview- und Frontend-Template referenzieren, statt sie doppelt zu pflegen.
8Wie vermeide ich Performance-Probleme?
loading="lazy" für Bilder, Intersection Observer für Slider, kein zusätzliches Bundle-JavaScript. Hyvä liefert ohnehin kein RequireJS aus.
9Wie migriere ich Luma-Inhalte auf Hyvä?
Master-Format bleibt unverändert, nur die Rendering-Schicht wechselt. Vorab alle genutzten Appearances auflisten und gegen vorhandene Hyvä-Templates abgleichen.
10Was passiert ohne passendes Hyvä-Template?
Ein generisches Fallback-Template greift und stellt Inhalte unformatiert oder unvollständig dar. Deshalb vor jedem Theme-Wechsel alle Appearances vollständig abgleichen.