WordPress theme.json bridge

How FDS coexists with WordPress global styles: preset-aliased emission and a generated theme.json settings fragment.

WordPress block themes have their own variable system (--wp--preset--*) generated from theme.json. FDS doesn't fight it — the bridge makes FDS sit on top of it, so a WP admin changing a palette color updates FDS-styled content too.

Preset-aliased emission

emitWpTheme(theme) emits the same stylesheet as emitTheme, except primitive color/space values are wrapped: instead of a literal, each declaration becomes var(--wp--preset--…, literal) — WordPress preset first, FDS literal as fallback. On a site without matching presets nothing changes; on a block theme, WP's palette wins.

import { emitWpTheme, wpPresetVar } from 'flexa-design-system';

wpPresetVar('color', 'fx-brand-600');
// '--wp--preset--color--fx-brand-600'

const css = emitWpTheme(defaultTheme());
// --fx-ref-brand-600: var(--wp--preset--color--fx-brand-600, #4f46e5);

The settings fragment

wpThemeJson() generates the matching theme.json settings fragment — the palette and spacing entries whose slugs line up with the preset vars above. A WP plugin merges it via the wp_theme_json_data_theme filter; the presets then appear in the native editor UI.

import { wpThemeJson } from 'flexa-design-system';

const fragment = wpThemeJson();
// { settings: { color: { palette: [{ slug: 'fx-brand-600', … }] }, … } }

Why only primitives

Only the primitive tier is bridged. Semantic tokens keep aliasing FDS primitives, so the FDS contract (naming, tiers, contrast pairs) stays intact regardless of what WordPress does — the bridge swaps where raw values come from, not how the system is wired.