Ein WordPress-Design-System ist die Menge an Tokens, erlaubten Editor-Steuerelementen und einfügbaren Layouts, die Gutenberg tatsächlich durchsetzt. Figma-Dateien setzen auf der veröffentlichten Website nichts durch. 2026 besteht dieser Vertrag aus theme.json Version 3, dem Ordner /patterns und einer kleinen Zahl von Custom Blocks. Alles andere ist ein Prototyp oder ein Datenbankobjekt, das Sie auch als solches behandeln müssen.
Auf großen Redaktionsseiten sehen wir immer wieder denselben Fehler: Das Markenhandbuch liegt in Figma, das CSS verteilt sich auf fünf Stylesheets, und der Editor bietet weiterhin einen freien Farbwähler an. Das Marketing bringt dann für eine Kampagne einen Hex-Wert heraus, der auf genau einer Landingpage existiert. Die nächste Kampagne kopiert ihn. Sechs Monate später kann niemand mehr sagen, welches Grün das Markengrün ist. Gutenberg kann das verhindern, aber nur, wenn Sie die Steuerelemente abschalten und die Palette in theme.json ablegen.
Dieser Text ist kein Plädoyer für eine Migration weg vom Page Builder. Wenn Sie zwischen Gutenberg, Elementor und Divi wählen, lesen Sie den Page-Builder-Vergleich 2026. Wenn Sie zwischen einem Block Theme und einem klassischen PHP-Theme wählen, lesen Sie klassische Themes vs. Block Themes. Hier geht es um die Ebene nach dieser Entscheidung: wie das System konsistent bleibt, wenn Redakteure jeden Tag im Inserter arbeiten.
theme.json Version 3 für ein Design-System einrichten
Die lebende Spezifikation ist theme.json Version 3. Eingeführt wurde sie mit WordPress 6.6: Der Beitrag im WordPress Developer Blog zu Section Styles hält fest, dass das Schema der Version 3 nur ab WordPress 6.6 unterstützt wird, oder mit dem Gutenberg-Plugin auf einem älteren Core. Ältere Dateien mit version: 2 werden weiterhin geladen. Neue Einstellungen kommen in Version 3. Eine Version 4 gibt es in dieser Spezifikation nicht, auch wenn viele Übersichten aus 2025 das behauptet haben.
Verweisen Sie in der Datei auf das Schema, das zur niedrigsten unterstützten WordPress-Version passt, nicht auf trunk, es sei denn, auf der Website läuft immer das Gutenberg-Plugin:
{
"$schema": "https://schemas.wp.org/wp/6.6/theme.json",
"version": 3,
"settings": {},
"styles": {}
}settings legt fest, was der Editor tun darf. styles ist das Standardaussehen, solange niemand einen Block überschreibt. Wer beides vermischt, liefert schnell einen hübschen Standard aus, den Redakteure trotzdem mit einem Klick zerstören können.
Für eine Website, die markenkonform bleiben muss, sieht der erste settings-Block bei uns so aus. Er schließt die freien Wähler für Farbe, Schriftgröße und Abstände und gibt dem Editor stattdessen feste Skalen:
{
"$schema": "https://schemas.wp.org/wp/6.6/theme.json",
"version": 3,
"settings": {
"color": {
"custom": false,
"customDuotone": false,
"customGradient": false,
"defaultPalette": false,
"defaultGradients": false,
"defaultDuotone": false,
"palette": [
{ "slug": "base", "name": "Base", "color": "#ffffff" },
{ "slug": "contrast", "name": "Contrast", "color": "#111111" },
{ "slug": "primary", "name": "Primary", "color": "#0b3d91" },
{ "slug": "accent", "name": "Accent", "color": "#c2410c" }
]
},
"typography": {
"customFontSize": false,
"dropCap": false,
"fontSizes": [
{ "slug": "small", "name": "Small", "size": "0.875rem" },
{ "slug": "medium", "name": "Medium", "size": "1rem" },
{ "slug": "large", "name": "Large", "size": "1.5rem" },
{ "slug": "x-large", "name": "Extra large", "size": "2.25rem" }
]
},
"spacing": {
"customSpacingSize": false,
"defaultSpacingSizes": false,
"spacingSizes": [
{ "slug": "20", "name": "XS", "size": "0.5rem" },
{ "slug": "30", "name": "S", "size": "1rem" },
{ "slug": "40", "name": "M", "size": "1.5rem" },
{ "slug": "50", "name": "L", "size": "2.5rem" },
{ "slug": "60", "name": "XL", "size": "4rem" }
]
}
}
}color.custom: false entspricht dem alten add_theme_support( 'disable-custom-colors' ). defaultPalette: false blendet die grauen und blauen Farbfelder des Core aus, sodass der Wähler nur Ihre Slugs zeigt. Die Zuordnung steht im Handbuch zu Global Settings and Styles. Bleiben diese beiden Schalter auf ihrem Standardwert (true), haben Sie kein Design-System. Sie haben einen Vorschlag.
customSpacingSize: false entfernt das freie Eingabefeld für Abstände, und defaultSpacingSizes: false verhindert, dass der Core neben Ihrer eigenen Skala eine weitere ergänzt. Beide Schlüssel stehen in der lebenden Referenz unter settings.spacing, direkt neben spacingSizes und spacingScale.
appearanceTools: true ist kein Sperrschalter. Die lebende Referenz listet auf, was er aktiviert: Hintergrundbild und Hintergrundgröße, Rahmenfarbe, Radius, Rahmenstil und Rahmenbreite, Link-, Überschriften-, Button- und Bildunterschriftenfarben, Seitenverhältnis, Höhe, Mindesthöhe, Mindestbreite und Breite, Sticky-Positionierung, Block-Abstand, Margin und Padding sowie Zeilenhöhe. Setzen Sie ihn ein, wenn Layoutarbeit in den Editor gehört. Lassen Sie ihn aus oder setzen Sie die einzelnen Schlüssel, wenn Abstände nur aus Presets kommen sollen.
Wie Gutenberg Presets aus theme.json in CSS-Variablen umwandelt
Jeder Slug der Palette wird zur Custom Property --wp--preset--color--{slug} und zu Utility-Klassen wie .has-{slug}-color und .has-{slug}-background-color. Schriftgrößen und Abstände folgen dem Muster --wp--preset--font-size--{slug} und --wp--preset--spacing--{slug}. Diese Benennung steht im selben Handbuch. Eigenes CSS im Theme sollte genau diese Variablen nutzen und keinen zweiten Satz von --brand-primary-Tokens, der mit der Zeit abweicht.
Werte ohne eigenen Preset-Typ, etwa Schattentiefen oder Eckenradien, denen Sie einen Namen geben wollen, kommen unter settings.custom. Das Handbuch dokumentiert, dass jeder Schlüssel dort zu einer Property --wp--custom--{key} wird, wobei verschachtelte Schlüssel mit einem doppelten Bindestrich verbunden werden. Ein kleiner Token-Satz für das Beispiel oben sieht im generierten CSS dann so aus:
/* Presets aus settings.color.palette und settings.typography.fontSizes */
--wp--preset--color--primary: #0b3d91;
--wp--preset--color--accent: #c2410c;
--wp--preset--font-size--large: 1.5rem;
/* Presets aus settings.spacing.spacingSizes */
--wp--preset--spacing--30: 1rem;
--wp--preset--spacing--40: 1.5rem;
/* Aus settings.custom: { "radius": { "card": "8px" } } */
--wp--custom--radius--card: 8px;Mehr steckt hinter “Design Tokens in Gutenberg” nicht. WordPress importiert kein Tokens Studio. Es erzeugt Presets aus theme.json. Hat das Designteam seine Tokens bereits als JSON, ist die ehrliche Pipeline ein Build-Schritt, der settings.color.palette (sowie die Skalen für Schrift und Abstände) in theme.json schreibt. Das Deployment liefert dann eine einzige Datei aus. Ein Webhook aus Figma, der ohne diesen Schreibschritt “in Produktion pusht”, ist eine Demo und kein System.
theme.json auf einer großen Website aufteilen
Child Themes mergen ihre theme.json über die des Parent Themes. Stilvariationen liegen als zusätzliche JSON-Dateien unter /styles. Per PHP lässt sich der Baum außerdem mit dem Filter wp_theme_json_data_theme anpassen, wenn eine Website im Netzwerk eine andere Primärfarbe braucht, ohne dass Sie das Theme forken. Diese drei Aufteilungen bringt der Core mit. Zwölf JSON-Teildateien in einem Node-Task zu kompilieren ist in Ordnung, wenn Ihr Team diesen Task ohnehin schon betreut. Nötig ist es nicht, und als WordPress-Funktion ist es auch nicht dokumentiert.
Entscheidet sich ein Team für den Weg über das Kompilieren, sieht die Struktur meist so aus:
theme/
├── theme.json (generated, committed)
├── config/
│ ├── color.json
│ ├── typography.json
│ ├── spacing.json
│ └── custom.json
└── build-theme-json.js (merges config/ into theme.json)Design, Entwicklung und Marketing können dann jeweils ihre eigenen Dateien bearbeiten, ohne Merge-Konflikte in einem großen JSON-Dokument. Der Preis: Das Merge-Skript wird zu Code, den jemand pflegen, testen und bei jeder Schemaänderung anpassen muss.
Mit Stilvariationen eine Palette ohne neues CSS tauschen
Eine alternative Palette braucht kein zweites Stylesheet. Der Weg im Core ist eine Stilvariation: eine JSON-Datei in /styles, die dieselben Slugs neu definiert. Der Websitebetreiber wählt sie im Website-Editor unter Stile aus, und jeder Block, der die Preset-Variablen bereits nutzt, zieht mit.
Stilvariation in /styles/dark.json:
{
"$schema": "https://schemas.wp.org/wp/6.6/theme.json",
"version": 3,
"title": "Dark",
"settings": {
"color": {
"palette": [
{ "slug": "base", "name": "Base", "color": "#111111" },
{ "slug": "contrast", "name": "Contrast", "color": "#f5f5f5" }
]
}
},
"styles": {
"color": {
"background": "var(--wp--preset--color--base)",
"text": "var(--wp--preset--color--contrast)"
}
}
}Die Variation behält die Slug-Namen und ändert nur deren Werte. Genau diese Regel lässt das Ganze funktionieren: Blöcke speichern den Slug, nicht den Hex-Wert. Einen automatischen Wechsel zwischen hellem und dunklem Modus auf Basis von prefers-color-scheme bringt der Core nicht mit. Dieses CSS schreiben Sie weiterhin selbst.
Seit WordPress 6.6 nimmt derselbe Ordner laut dem Beitrag im Developer Blog zu Block-Stilvariationen auch Variationen auf, die nur Farben oder nur die Typografie betreffen. Für eine Gruppe von Marken auf einer gemeinsamen Codebasis ergibt das eine saubere Trennung: gemeinsame Abstände und Layouts in der Haupt-theme.json, eine Variationsdatei pro Markenpalette.
Section Styles in theme.json seit WordPress 6.6
Vor 6.6 bedeutete ein eigener Blockstil wie “Boxed” für ein Pullquote eine CSS-Klasse plus handgeschriebenes CSS. Mit WordPress 6.3 ließen sich in theme.json nur die vom Core registrierten Blockstile bearbeiten. Im Beitrag im Developer Blog vom Juni 2024 erklärt Justin Tadlock, dass Sie seit WordPress 6.6 jede registrierte Block-Stilvariation in theme.json gestalten können, unter styles.blocks.{block}.variations.{name}, einschließlich der darin verschachtelten Elemente und Blöcke. Derselbe Beitrag beschreibt “Section Styles” als Konzept, das mit 6.6 eingeführt wurde: eine Block-Stilvariation, die auf einen Abschnitt angewendet wird, zusammen mit den verschachtelten Elementen und Blöcken, die sie neu gestaltet.
Ein Section Style lässt sich aus einer JSON-Datei in /styles registrieren (WordPress durchsucht auch Unterordner, /styles/section/ funktioniert also). Der Schlüssel blockTypes listet die Blöcke auf, für die er gilt:
{
"$schema": "https://schemas.wp.org/wp/6.6/theme.json",
"version": 3,
"slug": "section-dark",
"title": "Dark section",
"blockTypes": [ "core/group", "core/columns" ],
"styles": {
"color": {
"background": "var:preset|color|contrast",
"text": "var:preset|color|base"
},
"elements": {
"link": {
"color": { "text": "var:preset|color|accent" }
}
}
}
}Dieselbe Variation lässt sich auch in PHP registrieren. In 6.6 akzeptiert register_block_style() als erstes Argument ein Array von Blocknamen und einen Schlüssel style_data, der dieselbe Struktur wie die JSON-Datei aufnimmt:
register_block_style(
array( 'core/group', 'core/columns' ),
array(
'name' => 'section-dark',
'label' => __( 'Dark section', 'themeslug' ),
'style_data' => array(
'color' => array(
'background' => 'var:preset|color|contrast',
'text' => 'var:preset|color|base',
),
),
)
);Für ein Design-System ersetzt das die häufigste Quelle von Abweichungen: Redakteure, die Hintergrund- und Textfarbe in jeder Gruppe von Hand wählen. Mit Section Styles wählen sie “Dark section” im Bereich Stile, und die Kombination aus Hintergrund-, Text- und Linkfarbe stammt aus einer einzigen Definition. Eine globale Stilvariation kann diesen Abschnitt dann über die Eigenschaft styles.variations auf oberster Ebene neu abstimmen, sodass eine Markenvariation den dunklen Abschnitt zusammen mit allem anderen ändert. Derselbe Beitrag nennt eine Grenze, die Sie im Blick behalten sollten: Section Styles funktionieren am besten bei Container-Blöcken wie Gruppe, Spalten und Cover.
Theme-Patterns vs. synchronisierte Patterns in WordPress
An dieser Unterscheidung scheitern Projekte.
Die Einführung zu Patterns im Theme Handbook sagt es deutlich: Patterns, die Sie in /patterns ablegen, sind nicht synchronisiert. Sie sind Vorlagen für das nächste Einfügen. WordPress kopiert das Block-Markup in den Beitrag. Wenn Sie die PHP-Datei später ändern, bleiben bestehende Seiten unverändert. Dasselbe Handbuch ergänzt, dass synchronisierte Patterns nur im WordPress-Admin angelegt und verwaltet werden können.
Synchronisierte Patterns (vor WordPress 6.3 wiederverwendbare Blöcke) sind wp_block-Beiträge in der Datenbank. Sie legen sie im Editor an. Alle Instanzen bleiben im Gleichschritt. Diese Objekte liegen nicht in Git. Staging und Produktion brauchen jeweils denselben wp_block-Datensatz, sonst legen Sie die Patterns von Hand neu an.
Nutzen Sie diese Trennung bewusst:
| Art | Liegt in | Aktualisiert bestehende Seiten | Wandert zwischen Umgebungen |
|---|---|---|---|
Theme-Pattern (/patterns) | im Theme, in Git | nein | ja, mit dem Deployment |
| Synchronisiertes Pattern | in der Datenbank | ja | nur, wenn Sie die wp_block-Daten kopieren |
| Template-Teil (Header/Footer) | Theme-Datei bis zur Bearbeitung, danach Datenbank | ja, als Teil | als Datei, bis jemand ihn anpasst |
Heros, Layouts für Fallstudien und Grundgerüste für Landingpages gehören nach /patterns. Ein rechtlicher Hinweis, eine Cookie-Zeile oder ein Banner, den die Rechtsabteilung noch heute Nachmittag umschreiben kann, gehört in ein synchronisiertes Pattern, mit einem dokumentierten Export, damit Staging keine Überraschung bereithält.
Theme-Patterns registrieren Sie, indem Sie eine PHP-Datei mit Dateikopf in /patterns ablegen, so wie es das Kapitel Registering patterns empfiehlt, oder indem Sie register_block_pattern() auf init aufrufen. Ein Pattern, eine Methode. Registrieren Sie denselben Slug nicht zweimal.
In der Praxis hat eine Pattern-Bibliothek zwei Ebenen. Kleine Abschnitts-Patterns sind die Bausteine: ein Hero mit Überschrift, Einleitung, Button und Bild, eine Leistungskarte mit Icon, Titel, Text und Link, ein Testimonial mit Foto, Zitat, Name und Funktion, ein Call-to-Action-Banner. Ganzseitige Patterns setzen sie zu den Seitentypen zusammen, die das Marketing immer wieder braucht: eine Landingpage für eine Leistung, eine Fallstudie, eine Teamseite, eine Kontaktseite. Redakteure wählen ein ganzseitiges Pattern und ersetzen den Beispieltext, sodass eine neue Seite innerhalb der Markenregeln beginnt statt auf einer leeren Fläche.
Synchronisierte Patterns lohnen sich für Inhalte, die sich am selben Tag überall ändern müssen: rechtliche Hinweise, Einwilligungszeilen, Blöcke mit Firmenanschrift und Telefonnummer, der Call to Action der aktuellen Kampagne.
Pattern Overrides und die Block Bindings API verbinden Inhalte
Ein synchronisiertes Pattern war früher alles oder nichts: Entweder waren alle Instanzen identisch, oder Sie haben es gelöst und die Synchronisation verloren. WordPress 6.6 hat Overrides in synchronisierten Patterns eingeführt. In der Anleitung von Nick Diego im Developer Blog behält eine Karte ihr gemeinsames Design, während jede Instanz Überschrift, Text und Button ändert. Im Editor öffnen Sie das synchronisierte Pattern über “Original bearbeiten”, wählen einen Block aus, klicken im Bereich “Erweitert” des Block-Inspektors auf “Überschreibungen aktivieren” (“Enable overrides”) und vergeben einen eindeutigen Namen. Das Block-Markup enthält danach eine Bindung an die Quelle core/pattern-overrides.
Overrides stützen sich auf zwei ältere Mechanismen. Das reine Bearbeiten von Inhalten, eingeführt in WordPress 6.1, ist templateLock: "contentOnly" auf einem Container-Block: Nur verschachtelte Texte und Medien bleiben bearbeitbar, die Inspektor-Steuerelemente für Einstellungen und Stile sind deaktiviert. Der zweite Mechanismus ist die Block Bindings API, verfügbar seit WordPress 6.5, die ein Block-Attribut mit einer Datenquelle verbindet statt mit statischem Inhalt.
Das Handbuch listet auf, welche Core-Blöcke und Attribute standardmäßig Bindungen akzeptieren:
| Block | Bindbare Attribute |
|---|---|
| Bild | id, url, title, alt, caption |
| Überschrift, Absatz | content |
| Button | url, text, linkTarget, rel |
| Navigationslink, Navigations-Untermenü | url |
| Beitragsdatum | datetime |
Die eingebauten Quellen sind core/post-meta (der Meta-Schlüssel muss mit show_in_rest registriert sein und darf nicht mit einem Unterstrich beginnen), core/pattern-overrides und seit WordPress 6.9 core/post-data (Datum, Änderungsdatum und Link) sowie core/term-data. Ein Plugin kann mit register_block_bindings_source() auf init eine eigene Quelle hinzufügen und übergibt dabei ein label, ein optionales Array uses_context und einen get_value_callback. Die Bindung selbst steht in den metadata des Blocks:
<!-- wp:paragraph {"metadata":{"bindings":{"content":{"source":"core/post-meta","args":{"key":"product_sku"}}}}} -->
<p></p>
<!-- /wp:paragraph -->Für ein Design-System bleibt ein Pattern auf diese Weise ein Pattern, während seine Daten aus strukturierten Feldern kommen. Ein Pattern für eine Produktkarte kann seinen SKU-Absatz an Post-Meta binden, sodass Redakteure die SKU nie ins Layout tippen. Zwei Grenzen aus dem Handbuch sind hier wichtig. Die Registrierung im Editor mit registerBlockBindingsSource() kam mit 6.7, und ein gebundener Wert ist im Editor nur bearbeitbar, wenn die Quelle canUserEditValue bereitstellt. Der Beitrag zu Overrides hielt außerdem mit Stand Juni 2024 fest, dass synchronisierte Patterns nur in der Datenbank gespeichert werden und sich nicht als Pattern-Dateien in einem Theme ausliefern lassen. Erste Überlegungen dazu werden in einem Gutenberg-Issue verfolgt.
Theme-Patterns mit Git versionieren
WordPress versioniert Patterns nicht: Es gibt keine Status, keine Freigaben und keine automatische Migration bereits eingefügter Instanzen. Was es gibt, ist Git auf dem Ordner /patterns, und den Ablauf legt das Team fest:
- Entwurf: Das neue Pattern liegt auf einem Branch.
- Prüfung: Marke oder Rechtsabteilung geben es im Pull Request frei.
- Veröffentlicht: Es ist deployt und erscheint im Inserter.
- Ausgemustert: Es wird aus dem Inserter entfernt, indem Sie die Datei oder den Aufruf von
register_block_pattern()löschen. Seiten, die es bereits eingefügt haben, behalten ihr Markup, und die müssen Sie einzeln anfassen.
Schritt vier ist der Grund, die Zahl der Patterns klein zu halten. Jedes veröffentlichte Pattern hinterlässt Kopien im Inhalt, die das Theme nicht mehr erreicht.
Gutenberg-Vorlagen mit templateLock sperren
Eine Palette mit custom: false scheitert trotzdem, wenn die Seitenvorlage eine leere Gruppe ist und der Inserter jeden Core-Block anbietet. Für Seitentypen, die dem Modell treu bleiben müssen (Produkt, Standort, Dokumentation), sperren Sie die Vorlage: allowedBlocks auf der Gruppe, templateLock: "insert" oder "all", wo das Layout nicht umgestellt werden darf, und ein Pattern als Standardinhalt, damit der Editor nie mit einer leeren Fläche startet.
Die Referenz zu Block-Templates definiert die Werte. all verhindert das Einfügen, Verschieben und Löschen von Blöcken. insert verhindert das Einfügen und Entfernen von Blöcken, erlaubt aber das Verschieben vorhandener. contentOnly verhindert alle Operationen, blendet Blöcke ohne Inhalt in der Listenansicht aus und kann von Kind-Blöcken nicht überschrieben werden. Der Gruppen-Block deklariert templateLock als Attribut in seiner block.json, die Sperre kann also direkt im Markup einer Vorlage oder eines Patterns stehen.
Es gibt zwei weitere Ebenen. Ein einzelner Block kann ein Attribut lock mit den Schaltern move und remove tragen, und laut Referenz hat die Sperre auf Blockebene Vorrang vor templateLock. Ein Custom Post Type kann in register_post_type() ein eigenes template-Array und ein template_lock registrieren, sodass jedes neue Produkt mit derselben Blockstruktur beginnt.
Innerhalb eines Custom Blocks gilt dieselbe Sperre für seine Inner Blocks:
<InnerBlocks
template={ TEMPLATE }
templateLock="all"
allowedBlocks={ [ 'core/heading', 'core/paragraph', 'core/button' ] }
/>Redakteure können Texte und Bilder weiterhin ändern, aber keine Blöcke außerhalb der festgelegten Struktur umsortieren, entfernen oder hinzufügen.
Wann sich ein eigener Gutenberg-Block mit block.json lohnt
An dieser Stelle verdienen sich auch Custom Blocks ihren Platz. Core-Überschrift plus Absatz plus Bild decken die meisten Marketingmodule ab. Eine Vergleichstabelle, die eine SKU, eine Währung und ein Datum “zuletzt geprüft” tragen muss, braucht Attribute und Validierung über block.json. Wir bauen solche Blöcke mit @wordpress/scripts, halten das gespeicherte Markup schlicht und weigern uns, im Inspektor einen Page Builder nachzubauen. Ist der Block nur eine Hülle um Inner Blocks, nehmen Sie lieber ein Pattern.
Ein Block-Ordner im Repository des Design-Systems sieht so aus:
blocks/
└── product-comparison/
├── block.json
├── edit.js (editor UI)
├── save.js (front-end markup)
├── style.scss (front-end and editor styles)
└── editor.scss (editor-only styles)Die Referenz zu Block-Metadaten verwendet in ihrem Beispiel "apiVersion": 3. Sie sollten wissen, wo die Validierung in block.json endet. Laut Referenz zu Attributen enthält jede Attributdefinition mindestens einen type oder ein enum sowie die Angabe, woher der Wert gelesen wird. enum schränkt den gespeicherten Wert ein. Ein maxLength, minimum oder maximum, das Gutenberg für Sie durchsetzt, gibt es nicht:
{
"apiVersion": 3,
"name": "wppoland/product-comparison",
"attributes": {
"heading": { "type": "string", "default": "" },
"price": { "type": "number", "default": 0 },
"variant": {
"type": "string",
"enum": [ "primary", "secondary", "accent" ],
"default": "primary"
}
}
}Grenzen für Wertebereiche und Längen setzen Sie in der Edit-Komponente oder bei der REST-Validierung beim Speichern:
<RichText
tagName="h3"
value={ attributes.heading }
onChange={ ( heading ) => setAttributes( { heading: heading.slice( 0, 120 ) } ) }
/>Die Referenz zu @wordpress/scripts deckt den Rest der Toolchain mit einer einzigen Abhängigkeit ab. build erzeugt ein Produktions-Bundle, start baut bei jeder Änderung neu. lint-js und lint-style wenden die WordPress Coding Standards auf Skripte und Stylesheets an. test-e2e führt End-to-End-Tests mit Playwright aus, und plugin-zip packt das Plugin. Dasselbe Paket erkennt block.json-Dateien im Quellverzeichnis und nutzt sie als Einstiegspunkte, sodass ein neuer Block-Ordner keine Änderung an der Webpack-Konfiguration braucht.
Storybook für Gutenberg-UI-Komponenten nutzen
Das Gutenberg-Projekt dokumentiert seine eigenen UI-Komponenten in Storybook. Das README des Ordners storybook im Gutenberg-Repository hält fest, dass das Projekt “Storybook nutzt, um die in den WordPress-Paketen entwickelten UI-Komponenten anzuzeigen und mit ihnen zu arbeiten” (eigene Übersetzung), das Ergebnis unter wordpress.github.io/gutenberg veröffentlicht und es lokal mit npm run storybook:dev aus dem Wurzelverzeichnis des Repositorys startet.
Zwei Praktiken aus diesem README lassen sich gut auf das Design-System eines Kunden übertragen. Jede Komponentenseite deklariert einen Status (recommended, use-with-caution, not-recommended oder unaudited), der in der Seitenleiste erscheint, sodass Entwickler sehen, auf welchen Komponenten sie sicher aufbauen können. Außerdem committet das Repository einen Manifest-Snapshot aller Komponenten und ihrer Props: Ein Pull Request, der die Beschreibung einer Prop entfernt, schlägt fehl, bis jemand die Änderung bestätigt.
Was Storybook nicht abdeckt, ist die Inhaltsebene. Patterns, Presets aus theme.json und Section Styles werden im Block-Editor gerendert, deshalb ist die verlässliche Vorschau dafür eine Seite auf einer Staging-Website, die jedes Pattern einfügt und mit einem Redakteurskonto bearbeitet wird. Storybook passt zu den React-Teilen des Systems: den edit-Komponenten von Custom Blocks und allen gemeinsam genutzten Seitenleisten-Steuerelementen, die aus @wordpress/components gebaut sind, der Bibliothek, die das öffentliche Storybook dokumentiert.
Figma-Tokens nach theme.json übertragen
Eine offizielle Synchronisation zwischen Figma und WordPress gibt es nicht. Der Core liest keine Figma-Dateien, und kein Figma-Plugin schreibt von sich aus in eine Produktionswebsite. Was Sie bauen können, ist ein Build-Schritt: Die Tokens verlassen das Designwerkzeug als JSON, und ein Skript schreibt sie in theme.json, also in die Datei, die das Deployment ausliefert.
Die Namen passen anfangs fast nie zusammen, deshalb ist diese Zuordnung Code, den jemand pflegt. Ein Ablauf, der sich bewährt:
- Die Designerin oder der Designer ändert eine Farbe in Figma.
- Ein Token-Plugin exportiert die aktualisierten Tokens als JSON.
- Die CI führt das Build-Skript aus, das
settings.color.paletteintheme.jsonneu schreibt. - Visuelle Regressionstests vergleichen Screenshots vorher und nachher.
- Ein Mensch liest den Diff von
theme.jsonund genehmigt den Pull Request.
Halten Sie die Automatisierung bei Schritt fünf an. Ein Webhook, der die Produktion deployt, ohne dass jemand den Diff liest, ist eine Demo und kein System. Eine Markenfarbe ist genau die Art von Änderung, die eine Prüfung durch einen Menschen verdient.
| Werkzeug | Aufgabe | Was Sie weiterhin schreiben |
|---|---|---|
| Tokens Studio for Figma | Exportiert Tokens als JSON | Die Zuordnung von diesem JSON zu den settings in theme.json |
| Style Dictionary | Transformiert Tokens zwischen Plattformen | Ein eigenes Ausgabeformat für theme.json |
| GitHub Actions | Führt den Build aus und öffnet den Pull Request | Den Prüfschritt vor dem Merge |
| Playwright | Visueller Vergleich | Die Routen und Zustände, die erfasst werden |
Die Dokumentation fällt fast nebenbei aus Material ab, das ohnehin existiert: eine Seite auf der Website, die jedes Pattern der Bibliothek einfügt, die Git-Historie von /patterns und theme.json als Changelog und die Screenshots der visuellen Tests als Nachweis für vorher und nachher.
Barrierefreiheit in einem WordPress-Design-System prüfen
Nichts davon erledigt WordPress für Sie. Es sind Prüfungen, die Sie rund um das Theme aufbauen.
Die Palette ist eine kurze Liste von Hex-Werten in einer JSON-Datei, daher lässt sich der Kontrast im Build prüfen. Ein Test geht die erlaubten Paare aus Text und Hintergrund durch, berechnet das WCAG-Kontrastverhältnis und lässt den Build fehlschlagen, wenn ein Paar bei normalem Text unter 4.5:1 fällt. Er benennt die fehlerhafte Kombination per Slug, nicht per Hex-Wert, damit die Korrektur in theme.json landet. Der Block-Editor warnt bereits im Inspektor, wenn eine gewählte Farbkombination wenig Kontrast hat, aber diese Warnung verhindert das Veröffentlichen nicht. Section Styles helfen hier: Ist das Paar aus Hintergrund und Text einmal in einem Section Style definiert, wird es auch nur einmal getestet.
Lassen Sie in der CI axe-core gegen die wichtigsten Vorlagen und jede veröffentlichte Stilvariation laufen, und ergänzen Sie Tests zur Tastaturnavigation für Patterns mit interaktiven Elementen. Denken Sie an die Grenze: Automatische Werkzeuge erfassen nur einen Teil der WCAG-Kriterien. Der Rest bleibt eine manuelle Prüfung mit Tastatur und Screenreader.
Block-Assets im Block Theme bei Bedarf laden
Ein schlecht gebautes Design-System kann langsamer sein als eine handcodierte Website, weil jedes Pattern sein CSS mitschleppt. Der Core hilft, wenn Sie ihn lassen. In _add_default_theme_supports(), das für Block Themes läuft, fügt WordPress sowohl should_load_separate_core_block_assets als auch should_load_block_assets_on_demand als Filter mit __return_true hinzu (siehe wp-includes/theme.php in wordpress-develop). Der Docblock in script-loader.php beschreibt die Wirkung: Block-Assets werden nur geladen, wenn der Block gerendert wird. Ein klassisches Theme aktiviert das mit:
add_filter( 'should_load_separate_core_block_assets', '__return_true' );Eine Seite ohne Galerie lädt dann auch kein Galerie-CSS. Für Custom Blocks folgt daraus eine praktische Regel: Deklarieren Sie style, editorStyle, viewScript oder viewScriptModule in block.json, statt Dateien global aus functions.php einzubinden, damit WordPress sie nur dort lädt, wo der Block vorkommt. Was WordPress nicht tut, ist Critical CSS zu erzeugen oder ungenutzte Regeln zu entfernen. Das bleibt Aufgabe Ihres Builds oder einer Cache-Schicht.
Budgets pro Komponente sind eine Entscheidung des Teams und keine Messung des Core, und sie funktionieren nur, wenn jemand sie in jedem Pull Request prüft. Der günstigste Gewinn ist oft, gar kein Skript zu brauchen: Ein FAQ-Akkordeon auf Basis des Details-Blocks gibt <details> und <summary> aus, die sich ohne JavaScript öffnen und schließen lassen und mit der Tastatur funktionieren.
Checkliste für ein skalierbares WordPress-Design-System
Bei WordPress-Entwicklungsprojekten ist die Reihenfolge jedes Mal dieselbe:
- Tokens in
theme.jsonVersion 3, Farbwähler gesperrt, Core-Palette ausgeblendet. - Section Styles für die Paare aus Hintergrund und Text, damit Redakteure Gruppen nicht mehr von Hand einfärben.
- Ein kleiner Satz Patterns in
/patternsfür die Layouts, die das Marketing tatsächlich wiederholt. - Ein oder zwei synchronisierte Patterns für Texte, die der Rechtsabteilung gehören, exportiert mit der Inhaltssynchronisation und nie nach dem Motto “legen wir in Produktion neu an” liegen gelassen.
- Custom Blocks erst, wenn ein Pattern aus Core-Blöcken an einer echten Attributbedingung gescheitert ist.
- Eine Prüfung im Website-Editor mit einem Redakteurskonto, nicht mit einem Administratorkonto, weil Administratoren weiterhin Werkzeuge sehen, die Sie für ausgeblendet hielten.
Nutzt das Frontend bereits Utility-CSS, bleibt theme.json die Quelle der Tokens, und Sie bilden die Slugs in diesem CSS ab. Für Tailwind haben wir diese Aufteilung in Tailwind CSS in der WordPress-Entwicklung 2026 beschrieben. Gutenberg ist es egal, welches CSS-Framework --wp--preset--color--primary verwendet. Wichtig ist, dass Editor und Frontend denselben Slug benennen.
Das System funktioniert, wenn eine neue Landingpage ein eingefügtes Pattern ist, der Farbwähler acht Farbfelder hat und der Wunsch nach “nur diesem einen Orange” ein Pull Request gegen theme.json ist und kein Hex-Wert in einem Gruppen-Block.
Planen Sie ein Design-System auf WordPress? Schreiben Sie uns.






