theme.json není jen konfigurace. Je to API pro design systému WordPressu

Soubor theme.json se často bere jako „ten JSON, kam se píšou barvy a velikosti písma“. Jenže kdo s ním pracuje déle, zjistí, že jde o něco zásadnějšího. Je to veřejné, verzované a vrstvené rozhraní, přes které spolu komunikuje téma, editor, pluginy i samotný uživatel. Když ho tak začnete chápat, změní se i to, jak navrhujete a udržujete šablony.
Nálepky:
Od add_theme_support() k deklaraci
Starší generace WordPressových šablon řešila vzhled editoru imperativně. Ve functions.php se volalo add_theme_support( 'editor-color-palette', … ), add_theme_support( 'editor-font-sizes', … ), k tomu se přidal soubor editor-style.css a doufalo se, že výsledek v administraci bude alespoň trochu připomínat web. Každá z těchto funkcí řešila jeden izolovaný problém a mezi sebou o sobě nevěděly.
S příchodem blokového editoru se ukázalo, že tahle cesta nestačí. Editor potřeboval vědět nejen to, jaké barvy téma nabízí, ale také které ovládací prvky má zobrazit, jaké výchozí styly mají jednotlivé bloky, jak široký je obsah, jaké jsou mezery a jak to všechno propsat do CSS na webu i v editoru stejným způsobem. Odpovědí byl WordPress 5.8 a soubor theme.json, který se od té doby postupně rozrostl do dnešní podoby.
Klíčový posun není v tom, že se nastavení přesunulo z PHP do JSONu. Klíčové je, že se z imperativních volání stala deklarace. Téma už neříká „zavolej tuhle funkci“, ale „tohle je můj design systém“. A deklaraci může číst kdokoli: jádro, editor, plugin, nástroj pro build nebo linter.
Anatomie jednoho souboru
Minimální theme.json vypadá nenápadně:
{
"$schema": "https://schemas.wp.org/wp/6.9/theme.json",
"version": 3,
"settings": {},
"styles": {},
"customTemplates": [],
"templateParts": [],
"patterns": []
}Code language: JSON / JSON with Comments (json)
Už tady se ale skrývá první náznak toho, že nejde o obyčejný konfigurační soubor. Máme tu dvě různá „verzování“, která si lidé často pletou.
Klíč version je verze samotného API. Zvyšuje se pokaždé, když je potřeba udělat nekompatibilní změnu, a téma se k takové změně přihlašuje tím, že verzi aktualizuje; starší verze zůstávají v nových WordPressech podporované. To je přesně chování, jaké očekáváme od dobře navrženého API: změny chování nejsou tiché, ale explicitní.
Naproti tomu $schema slouží vašemu editoru kódu. Schéma je navázané na konkrétní verzi WordPressu, takže když uvedete minimální podporovanou verzi, našeptávání a validace vám ukážou jen vlastnosti, které v ní skutečně existují. Jinými slovy: version říká WordPressu, jak má soubor interpretovat, $schema říká vývojáři, co smí použít.
Zbytek souboru se dělí na dvě hlavní oblasti. settings popisuje, co je k dispozici – palety, škály, povolené nástroje. styles popisuje, jak se to použije – jaká barva má text, jak vypadá tlačítko, jaké má nadpis písmo. Pole customTemplates, templateParts a patterns pak registrují šablony, části šablon a vzory z adresáře vzorů. Toto rozdělení na „nabídku“ a „aplikaci“ je jádrem celého konceptu.
settings: smlouva mezi tématem a editorem
Sekce settings je v podstatě smlouva. Téma v ní říká editoru, jaké volby smí uživatel vidět a jaké hodnoty jsou legitimní součástí design systému.
{
"version": 3,
"settings": {
"appearanceTools": true,
"layout": {
"contentSize": "42rem",
"wideSize": "72rem"
},
"color": {
"defaultPalette": false,
"custom": false,
"palette": [
{ "slug": "base", "color": "#ffffff", "name": "Základ" },
{ "slug": "contrast", "color": "#111827", "name": "Kontrast" },
{ "slug": "accent", "color": "#0b5fff", "name": "Akcent" }
]
},
"typography": {
"fluid": true,
"fontSizes": [
{ "slug": "small", "size": "0.875rem", "name": "Malé" },
{ "slug": "large", "size": "1.5rem", "name": "Velké",
"fluid": { "min": "1.25rem", "max": "1.75rem" } }
]
},
"custom": {
"lineHeight": { "tight": 1.1, "relaxed": 1.7 }
}
}
}Code language: JSON / JSON with Comments (json)
Na první pohled je to seznam hodnot. Ve skutečnosti se tu děje několik věcí najednou.
Zaprvé, každý preset se automaticky promítne do CSS vlastnosti. Z palety vznikne --wp--preset--color--accent, z velikosti písma --wp--preset--font-size--large, ze sekce custom pak --wp--custom--line-height--tight (všimněte si převodu z camelCase do kebab-case). Tyto proměnné jsou dostupné na webu i v editoru a představují stabilní rozhraní, na které se může odkazovat CSS tématu, CSS pluginu i inline styly bloků. Slug presetu je tedy veřejný identifikátor. Když ho přejmenujete, rozbijete kompatibilitu podobně, jako když přejmenujete veřejnou metodu třídy.
Zadruhé, settings řídí uživatelské rozhraní. Nastavení "custom": false odstraní z editoru výběr libovolné barvy a "defaultPalette": false skryje výchozí paletu jádra. Uživatel pak může volit jen z barev, které jsou součástí design systému. Tady theme.json přestává být konfigurací vzhledu a stává se nástrojem governance: určuje, kde končí svoboda redaktora a začíná konzistence značky.
Zatřetí, nastavení lze definovat i na úrovni jednotlivých bloků. Pod klíčem settings.blocks můžete například povolit vlastní barvy jen pro blok core/cover, nebo naopak skupině core/group nabídnout jinou paletu. Design systém tak nemusí být plochý – může mít kontextová pravidla.
styles: tokeny v akci
Zatímco settings definuje slovník, styles z něj skládá věty. Místo psaní CSS selektorů popisujete styly strukturovaně podle toho, na co se vztahují: na celý web, na HTML elementy, nebo na konkrétní bloky.
{
"version": 3,
"styles": {
"color": {
"background": "var:preset|color|base",
"text": "var:preset|color|contrast"
},
"typography": {
"lineHeight": "var(--wp--custom--line-height--relaxed)"
},
"elements": {
"link": {
"color": { "text": "var:preset|color|accent" },
":hover": { "typography": { "textDecoration": "none" } }
},
"heading": {
"typography": { "lineHeight": "var(--wp--custom--line-height--tight)" }
}
},
"blocks": {
"core/button": {
"color": {
"background": { "ref": "styles.elements.link.color.text" },
"text": "var:preset|color|base"
}
}
}
}
}Code language: JSON / JSON with Comments (json)
Stojí za to zastavit se u dvou syntaktických detailů, protože právě ony ukazují, že jde o API, a ne o přepis CSS do JSONu.
Zápis var:preset|color|accent je interní reference na preset. WordPress ji při generování stylů převede na var(--wp--preset--color--accent), ale editor díky ní ví, že hodnota pochází z palety, a v rozhraní ji zobrazí jako vybranou barvu. Kdybyste napsali přímo hex kód, výsledek by na webu vypadal stejně, ale vazba na design token by se ztratila.
Konstrukce { "ref": "styles.elements.link.color.text" } jde ještě dál: odkazuje na jinou hodnotu uvnitř stromu stylů. Tlačítko tu nemá „modrou barvu“, ale „stejnou barvu jako odkaz“. Když se změní odkaz – třeba proto, že si uživatel v globálních stylech vybere jinou barvu –, tlačítko ho následuje. To je sémantická vazba, kterou v čistém CSS vyjádříte jen s disciplínou a konvencemi.
Sekce styles se navíc v posledních verzích výrazně rozšiřuje. Dlouho platilo, že stavy jako :hover šly deklarovat jen u elementů, a u bloků bylo nutné sáhnout po vlastním CSS. WordPress 7.0 přidal podporu pseudotříd :hover, :focus, :focus-visible a :active přímo na blocích a jejich stylových variantách, přičemž jde čistě o rozhraní v theme.json – odpovídající ovládání v globálních stylech zatím v této verzi není. I to je typický vzorec: API se objeví dřív než UI, protože UI je jen jedním z jeho konzumentů. Podobně přibyla typografická vlastnost pro odsazení prvního řádku odstavců, kterou lze nastavit i globálně přes theme.json a zvolit, zda se odsazují všechny odstavce, nebo jen ty následující.
Vrstvy: kaskáda dat, ne jen kaskáda stylů
Nejdůležitější vlastnost, kterou běžný konfigurační soubor nemá, je vrstvení. Data z theme.json nevznikají z jednoho souboru, ale ze sloučení několika zdrojů v pevně daném pořadí:
- default – výchozí hodnoty jádra WordPressu,
- blocks – data, která deklarují bloky (typicky přes
block.json), - theme –
theme.jsonrodičovského tématu, případně přepsaný tématem podřízeným, - custom (user) – úpravy, které uživatel provede v editoru webu a které se ukládají do databáze jako příspěvek typu
wp_global_styles.
Pozdější vrstva přepisuje dřívější. O sloučení se stará třída WP_Theme_JSON_Resolver a výsledkem je jeden strom, ze kterého se generuje CSS i konfigurace editoru.
Tahle architektura má praktické důsledky. Podřízené téma nemusí kopírovat celý soubor – stačí mu theme.json jen s tím, co mění. Uživatelské úpravy nikdy nepřepíšou soubor tématu, takže aktualizace tématu je bezpečná. A protože každá vrstva je oddělená, lze se do každé z nich programově vložit.
Presety si přitom pamatují svůj původ. Paleta ve výsledném stromu není jedno pole, ale objekt s klíči default, theme a custom. Díky tomu editor umí zobrazit barvy tématu odděleně od barev, které si přidal uživatel. S tím souvisí i poslední velká změna chování: ve verzi 3, kterou přinesl WordPress 6.6, už presety tématu ve výchozím stavu nepřepisují výchozí presety jádra a přibyly nové vlastnosti, jimiž se toto chování konfiguruje (například defaultFontSizes a defaultSpacingSizes). Právě kvůli takovým změnám existuje klíč version.
Filtry: programové rozhraní nad deklarací
Kdyby theme.json byl jen statický soubor, narazili byste rychle na limity. Co když má paleta záviset na nastavení pluginu? Co když redaktoři nemají vidět stejné volby jako administrátoři? Pro tyto případy nabízí WordPress (od verze 6.1) čtveřici filtrů, z nichž každý odpovídá jedné vrstvě: wp_theme_json_data_default, wp_theme_json_data_blocks, wp_theme_json_data_theme a wp_theme_json_data_user.
Filtr dostane objekt typu WP_Theme_JSON_Data a vrací ho upravený metodou update_with():
add_filter( 'wp_theme_json_data_theme', function ( $theme_json ) {
$brand_color = get_option( 'mytheme_brand_color', '#0b5fff' );
return $theme_json->update_with( array(
'version' => 3,
'settings' => array(
'color' => array(
'palette' => array(
array(
'slug' => 'accent',
'color' => sanitize_hex_color( $brand_color ),
'name' => __( 'Akcent', 'mytheme' ),
),
),
),
),
) );
} );Code language: PHP (php)
A takto lze omezit nástroje podle role uživatele:
add_filter( 'wp_theme_json_data_theme', function ( $theme_json ) {
if ( current_user_can( 'edit_theme_options' ) ) {
return $theme_json;
}
return $theme_json->update_with( array(
'version' => 3,
'settings' => array(
'typography' => array(
'customFontSize' => false,
'fontFamilies' => array(),
),
'spacing' => array(
'customSpacingSize' => false,
),
),
) );
} );Code language: PHP (php)
Všimněte si, že i filtr pracuje se stejnou strukturou včetně klíče version. Nevznikají tu nové funkce pro každou vlastnost; existuje jeden datový model a jeden způsob, jak ho rozšířit. To je rozdíl mezi „sadou háčků“ a skutečným API.
Čtení dat: PHP i JavaScript
API, které jde jen zapisovat, by bylo poloviční. Výsledný sloučený strom lze číst na serveru i v editoru.
V PHP slouží k tomu funkce wp_get_global_settings() a wp_get_global_styles(), obě přijímají cestu ve formě pole a volitelný kontext:
$theme_palette = wp_get_global_settings( array( 'color', 'palette', 'theme' ) );
$text_color = wp_get_global_styles( array( 'color', 'text' ) );Code language: PHP (php)
Plugin tak může například vygenerovat e-mailovou šablonu v barvách aktuálního tématu, aniž by musel znát jeho implementaci. Pro celé vygenerované CSS existuje wp_get_global_stylesheet().
V editoru pak vlastní blok sáhne po hooku useSettings z balíčku @wordpress/block-editor:
import { useSettings } from '@wordpress/block-editor';
export default function Edit() {
const [ palette, fontSizes ] = useSettings(
'color.palette',
'typography.fontSizes'
);
// …
}Code language: JavaScript (javascript)
Hook respektuje kontext bloku, takže vrátí nastavení platná pro konkrétní typ bloku a místo, kde se nachází. Blok napsaný třetí stranou tak automaticky „mluví“ jazykem tématu, do kterého je vložený. A naopak: blok, který v block.json deklaruje podporu (supports) pro barvy, typografii nebo mezery, dostane odpovídající ovládací prvky řízené právě tím, co téma povolilo v settings. Blok nabízí schopnost, téma rozhoduje o jejím použití.
Stylové varianty a section styles
Další vrstvou abstrakce jsou soubory v adresáři styles/ tématu. Každý z nich má stejnou strukturu jako theme.json a představuje alternativní variantu design systému – tmavý režim, jinou značku, sezónní kampaň. Uživatel je přepíná v editoru webu a vybraná varianta se sloučí nad daty tématu.
Od WordPressu 6.6 mohou tyto soubory být i dílčí: varianta může obsahovat pouze barevnou paletu nebo pouze typografické presety a editor je nabídne odděleně. Téma tak může nabídnout například pět palet a tři typografické sady, které lze libovolně kombinovat, aniž by autor musel připravit patnáct úplných variant.
Stejná verze přinesla také tzv. section styles, tedy stylové varianty bloků definované přímo v datech theme.json. Blok skupiny s variantou „zvýrazněná sekce“ může uvnitř sebe přenastavit barvy textu, odkazů, tlačítek i nadpisů. Z pohledu design systému jde o kontextové tokeny: stejná sémantická role („text“, „akcent“) má v různých sekcích různé hodnoty, a vnořené bloky to přitom nemusí vůbec řešit.
Kde to drhne
Bylo by nepoctivé tvrdit, že theme.json je dokonalé API. Má svá omezení a v praxi na ně narazíte.
JSON nepodporuje komentáře. U velkých design systémů to znamená, že vysvětlení, proč má tlačítko zrovna tuhle barvu, musí žít jinde. Řada týmů proto theme.json negeneruje ručně, ale sestavuje ho při buildu z menších souborů nebo z tokenů exportovaných z návrhových nástrojů (například pomocí Style Dictionary). To je mimochodem další argument pro chápání theme.json jako rozhraní: jde o cílový formát, do kterého lze kompilovat.
Specificita generovaného CSS se v průběhu verzí měnila a WordPress ji dnes drží nízko (s využitím :where()), aby šly styly snadno přepsat. To je dobře pro rozšiřitelnost, ale znamená to, že neopatrně napsané CSS pluginu může design systém nechtěně přebít.
Ne všechno jde vyjádřit deklarativně. Složitější layouty, animace nebo stavy závislé na JavaScriptu stále vyžadují vlastní CSS. Pro drobné úpravy existuje vlastnost styles.css (globálně i na úrovni bloku), ale je to únikový východ, ne cílový stav. Každé pravidlo schované v textovém řetězci CSS je pro editor neviditelné a uživatel ho nemůže změnit v rozhraní.
A konečně: vrstvení je silné, ale může být matoucí. Když se barva „nechce změnit“, bývá příčinou uživatelská úprava uložená v databázi, která přepisuje soubor tématu. Při ladění se vyplatí nejprve zkontrolovat, co je ve vrstvě custom, a teprve pak podezírat vlastní kód.
Jak s theme.json pracovat jako s API
Z předchozího vyplývá několik praktických zásad. Zacházejte se slugy presetů jako s veřejnými identifikátory: volte sémantické názvy (accent, contrast, surface) místo popisných (blue, dark-gray) a neměňte je bez rozmyslu, protože na ně odkazuje uložený obsah. Když se v příspěvku uloží blok s třídou has-accent-color, bude ji potřebovat i za tři roky.
Uvádějte $schema odpovídající minimální podporované verzi WordPressu a version aktualizujte vědomě, s přečtením poznámek k nekompatibilním změnám. Upřednostňujte reference na presety (var:preset|…) a ref před natvrdo zapsanými hodnotami, aby editor i uživatel viděli vazby. Omezení voleb v settings berte jako součást návrhu, ne jako dodatečnou restrikci: dobrý design systém nenabízí nekonečný výběr, ale správné možnosti. A dynamickou logiku řešte filtry nad datovými vrstvami, nikoli generováním CSS mimo systém globálních stylů.
Závěr
theme.json začínal jako náhrada několika volání add_theme_support(). Dnes je to verzované rozhraní se schématem, datovým modelem rozděleným do vrstev, programovými body pro zápis i čtení na serveru a v editoru a s vlastní sémantikou referencí. Téma přes něj publikuje design systém, bloky ho konzumují, pluginy ho rozšiřují a uživatel ho v rámci povolených mantinelů upravuje.
Pokud ho budete dál brát jako konfigurační soubor, budete v něm „nastavovat barvy“. Pokud ho začnete brát jako API, budete v něm navrhovat smlouvu – mezi designérem a vývojářem, mezi tématem a pluginem, mezi značkou a redaktorem. A to je rozdíl, který je na výsledném webu vidět.
… liked this!