Wer ein WordPress-Block-Theme entwickelt, kommt an theme.json nicht vorbei. Die Datei liegt im Theme-Stammverzeichnis und bündelt globale Farben, Typografiesystem, Abstände, Layout-Breiten und Schriftdateien an einer Stelle. WordPress selbst beschreibt sie als gemeinsame Sprache zwischen Theme, Core, Plugins und Bedienoberfläche. Damit ersetzt theme.json nicht grundsätzlich functions.php oder klassische Theme-Logik, übernimmt aber einen großen Teil dessen, was früher über verteilte PHP-Filter und manuell gepflegte CSS-Variablen gelöst wurde.
Die eigentlich interessante Idee liegt eine Ebene tiefer. Eine Farbpalette in theme.json legt nicht nur fest, wie eine Website aussieht, sie legt fest, was die Website überhaupt darstellen kann und welche dieser Möglichkeiten eine Redakteurin im Editor auswählen darf. primary ist nicht bloß #005fa3, sondern eine Entscheidung, die sich durch CSS, Editor-Oberfläche und Redaktionsworkflow zieht. Wer diese Perspektive einmal verinnerlicht hat, liest jede Zeile in theme.json anders, auch die scheinbar simplen.
Eine minimale theme.json besteht aus drei Bereichen:
{
"$schema": "https://schemas.wp.org/trunk/theme.json",
"version": 3,
"settings": {},
"styles": {}
}
$schema aktiviert IDE-Autovervollständigung und Validierung in VS Code und PhpStorm. version: 3 wurde mit WordPress 6.6 eingeführt und ist auch unter WordPress 7.0 weiterhin die aktuelle Version der Spezifikation, eine Version 4 gibt es bislang nicht. settings definiert, welche Optionen im Editor verfügbar sind und welche Presets generiert werden. styles wendet globale Stile auf Elemente, Blöcke und die gesamte Seite an. WordPress übersetzt diese Angaben in das Global-Styles-System, in CSS Custom Properties und in die entsprechenden Editor-Einstellungen.
Der settings-Bereich ist der größte und wichtigste Teil. Hier entstehen die Farbpalette, das Typografiesystem und die Layout-Grundmaße, die im gesamten Projekt konsistent verfügbar sind. Und hier zeigt sich die Governance-Funktion von theme.json am deutlichsten: Dieses Projekt hat vier definierte Farben, also bietet das Interface im Color Picker auch nur vier Farben an. Ein Teil der gestalterischen Beliebigkeit wird verhindert, bevor sie überhaupt ins CSS gelangen könnte.
{
"settings": {
"color": {
"defaultPalette": false,
"palette": [
{ "slug": "primary", "color": "#005fa3", "name": "Primär" },
{ "slug": "secondary", "color": "#333333", "name": "Sekundär" },
{ "slug": "background", "color": "#ffffff", "name": "Hintergrund" },
{ "slug": "accent", "color": "#e8f0fe", "name": "Akzent" }
]
},
"typography": {
"defaultFontSizes": false,
"fluid": true,
"fontFamilies": [
{
"slug": "inter",
"name": "Inter",
"fontFamily": "Inter, sans-serif",
"fontFace": [
{
"fontFamily": "Inter",
"fontWeight": "400",
"fontStyle": "normal",
"fontDisplay": "swap",
"src": ["file:./fonts/Inter-Regular.woff2"]
},
{
"fontFamily": "Inter",
"fontWeight": "700",
"fontStyle": "normal",
"fontDisplay": "swap",
"src": ["file:./fonts/Inter-Bold.woff2"]
}
]
}
],
"fontSizes": [
{ "slug": "small", "size": "0.875rem", "name": "Klein" },
{ "slug": "base", "size": "1rem", "name": "Basis" },
{ "slug": "large", "size": "1.25rem", "name": "Groß" },
{ "slug": "x-large", "size": "1.5rem", "name": "Sehr groß" },
{ "slug": "huge", "size": "2rem", "name": "Riesig" }
]
},
"layout": {
"contentSize": "720px",
"wideSize": "1200px"
},
"spacing": {
"spacingSizes": [
{ "slug": "small", "size": "1rem", "name": "Klein" },
{ "slug": "medium", "size": "2rem", "name": "Mittel" },
{ "slug": "large", "size": "4rem", "name": "Groß" }
]
}
}
}
defaultPalette: false und defaultFontSizes: false deaktivieren die Standardpalette und Standard-Schriftgrößen von WordPress im Editor. Ohne diese beiden Zeilen stehen die eigenen Presets neben den Core-Werten, und im Color Picker landen Farben, die im Designsystem des Projekts gar nicht vorgesehen sind.
Jeder Eintrag in settings erzeugt automatisch eine CSS Custom Property nach folgendem Schema:
--wp--preset--{typ}--{slug}
Aus der Farbpalette oben entstehen zum Beispiel:
--wp--preset--color--primary: #005fa3;
--wp--preset--color--secondary: #333333;
--wp--preset--color--background: #ffffff;
--wp--preset--color--accent: #e8f0fe;
Aus den Schriftgrößen:
--wp--preset--font-size--small: 0.875rem;
--wp--preset--font-size--base: 1rem;
--wp--preset--font-size--large: 1.25rem;
--wp--preset--font-size--x-large: 1.5rem;
--wp--preset--font-size--huge: 2rem;
Diese Properties stehen in Stylesheets, Block-Templates und in den styles von theme.json selbst zur Verfügung. Einmal definiert, konsistent überall verwendbar.
styles übersetzt die Presets in konkrete CSS-Regeln. Hier wird festgelegt, welche Farbe, Schrift und Zeilenhöhe die gesamte Seite, einzelne HTML-Elemente und Blöcke erhalten.
{
"styles": {
"color": {
"background": "var(--wp--preset--color--background)",
"text": "var(--wp--preset--color--secondary)"
},
"typography": {
"fontFamily": "var(--wp--preset--font-family--inter)",
"fontSize": "var(--wp--preset--font-size--base)",
"lineHeight": "1.65"
},
"elements": {
"link": {
"color": { "text": "var(--wp--preset--color--primary)" },
":hover": {
"color": { "text": "var(--wp--preset--color--secondary)" }
}
},
"h1": {
"typography": {
"fontSize": "var(--wp--preset--font-size--huge)",
"fontWeight": "700",
"lineHeight": "1.2"
}
},
"h2": {
"typography": {
"fontSize": "var(--wp--preset--font-size--x-large)",
"fontWeight": "700",
"lineHeight": "1.3"
}
}
}
}
}
Über elements lassen sich definierte HTML-Elemente wie h1 bis h6, link, button, caption und heading direkt in theme.json stylen. Das Global-Styles-System kennt dafür nur eine feste Liste definierter Elementtypen und adressiert keine beliebigen HTML-Elemente.
WordPress 6.9 hat diese Liste um select und textInput erweitert, allerdings mit noch unvollständiger Unterstützung: Gerade :focus bei den neueren Form-Elementen lässt sich darüber noch nicht steuern. Wer Formulare stylen will, kommt an eigenem CSS für diese Zustände aktuell nicht vorbei.
Für Blöcke selbst gilt seit WordPress 7.0 eine großzügigere Regel: Pseudo-Klassen wie :hover, :focus, :focus-visible und :active lassen sich jetzt direkt auf Block-Ebene und für Block-Style-Variationen definieren, nicht mehr nur bei den klassischen Elementen link und button.
{
"styles": {
"blocks": {
"core/button": {
"color": { "background": "var(--wp--preset--color--accent)" },
":hover": {
"color": { "background": "var(--wp--preset--color--accent-2)" }
},
":focus-visible": {
"outline": {
"width": "2px",
"style": "solid",
"color": "currentColor",
"offset": "2px"
}
}
}
}
}
}
Seit WordPress 6.1 kann theme.json Schriftgrößen automatisch als clamp()-Werte ausgeben. Bei aktiviertem fluid: true auf Ebene der Typografie-Settings genügt es, min und max pro Schriftgröße anzugeben:
WordPress berechnet daraus einen clamp()-Ausdruck und schreibt ihn in die generierten Styles. Kein manuelles clamp() mehr, keine separaten Media Queries für Schriftgrößen.
Über settings.custom lassen sich beliebige CSS Custom Properties anlegen. WordPress übernimmt dabei sogar die Namenskonvertierung: lineHeight als camelCase-Schlüssel wird automatisch zu --wp--custom--line-height.
{
"settings": {
"custom": {
"lineHeight": {
"body": "1.65",
"heading": "1.2"
},
"borderRadius": {
"small": "4px",
"medium": "8px"
}
}
}
}
Erzeugt:
--wp--custom--line-height--body: 1.65;
--wp--custom--line-height--heading: 1.2;
--wp--custom--border-radius--small: 4px;
--wp--custom--border-radius--medium: 8px;
Verschachtelte Objekte werden mit doppeltem Bindestrich verbunden, beliebig tief. In theme.json-Styles lassen sich diese Werte direkt referenzieren, etwa über var:custom|line-height|body statt der ausgeschriebenen CSS-Variable.
theme.json im Theme-Stammverzeichnis ist heute nicht mehr die einzige Konfigurationsdatei eines Projekts. Im Unterverzeichnis /styles lassen sich zusätzliche JSON-Dateien ablegen, die Farb-, Typografie- oder komplette Theme-Variationen definieren und im Editor als wählbare Stilvarianten auftauchen. Jede Variation überschreibt gezielt einzelne Werte der Basis, ohne die restliche Konfiguration zu duplizieren.
{
"$schema": "https://schemas.wp.org/trunk/theme.json",
"version": 3,
"title": "Dunkel",
"settings": {
"color": {
"palette": [
{ "slug": "background", "color": "#1a1a1a", "name": "Hintergrund" },
{ "slug": "primary", "color": "#4da6ff", "name": "Primär" }
]
}
}
}
Damit wird aus theme.json weniger eine statische Konfiguration und mehr ein vererbbares Designsystem: eine Basis, auf die spezifischere Varianten aufsetzen und deren Werte gezielt überschreiben. Für Projekte mit mehreren Marken-Ausprägungen oder saisonalen Anpassungen ist das der sauberere Weg gegenüber mehreren komplett eigenständigen theme.json-Dateien.
In einem ernsthaft entwickelten Block-Theme ist theme.json heute die zentrale Design-Konfiguration, auch wenn sie technisch nicht zwingend erforderlich ist. defaultPalette: false und defaultFontSizes: false gehören von Anfang an dazu, damit die eigenen Presets nicht neben den WordPress-Standardwerten stehen. Fluid Typography lässt sich seit WordPress 6.1 direkt in theme.json lösen, ganz ohne manuelles clamp(). Und mit Style Variations wird aus der einen Konfigurationsdatei ein System, das eine Basis definiert und beliebig viele Varianten darauf aufbauen lässt. Am Ende steht immer dieselbe Frage: nicht nur, wie etwas aussehen soll, sondern welche gestalterischen Entscheidungen im Projekt überhaupt zur Wahl stehen.