Skip to content

Global Styles: kebab-case preset slugs when converting references to custom properties#80583

Open
jorgefilipecosta wants to merge 5 commits into
trunkfrom
fix/global-styles-preset-slug-kebab-case
Open

Global Styles: kebab-case preset slugs when converting references to custom properties#80583
jorgefilipecosta wants to merge 5 commits into
trunkfrom
fix/global-styles-preset-slug-kebab-case

Conversation

@jorgefilipecosta

@jorgefilipecosta jorgefilipecosta commented Jul 22, 2026

Copy link
Copy Markdown
Member

What?

Fixes #53695.

When a preset slug changes under kebab-casing (e.g. a font family with slug n27), styles referencing that preset from theme.json or Global Styles never apply on the front end. The same mismatch affects every preset type referenced this way: colors, gradients, font sizes, font families, spacing, shadows.

This PR fixes it in the one place responsible: the PHP conversion of stored preset references to CSS custom properties.

Why?

PHP kebab-cases the slug in one place but not in the other:

  • When generating the preset custom properties, the slug is kebab-cased with _wp_to_kebab_case() — see get_settings_values_by_slug():

    --wp--preset--font-family--n-27: N27, sans-serif;
  • When converting stored references (var:preset|font-family|n27) to var() usages, convert_custom_properties() performs a verbatim |-- string replacement with no kebab-casing:

    font-family: var(--wp--preset--font-family--n27); /* this custom property does not exist */

The declared name has n-27, the reference asks for n27, so the browser finds no such custom property and the style falls back. For slugs that don't change under kebab-casing (vivid-red, x-large, 40) the two paths coincidentally agree, which is why the bug only surfaces with slugs like n27.

convert_custom_properties() is the odd one out among all the serializers: the PHP block supports / style engine (wp_typography_get_preset_inline_style_value(), WP_Style_Engine::get_slug_from_preset_value()) kebab-case — which is why block-level markup renders correctly — and so do the client-side style engine and global styles engine, which is why the editor canvas renders correctly. Only this Global Styles reference conversion disagrees.

How?

convert_custom_properties() now kebab-cases the slug segment of var:preset|<type>|<slug> references with the same _wp_to_kebab_case() the custom property generation uses, so both sides always agree. Only exact three-segment preset references are touched; any other var: value converts byte-identically to before.

Backward compatibility

References that render correctly today are provably unchanged: a reference only works today when its raw slug already equals the kebab-cased declaration name (i.e. the slug is a kebab-case fixed point), and _wp_to_kebab_case() is the identity on exactly those slugs. Since both sides use the same function, the change can only converge a reference toward its declaration — never move a matching one away.

The behavioral deltas are limited to references that are currently dead:

  • They start resolving — the bug fix itself, but it is a rendering change on existing sites whose chosen preset silently fell back until now (dev note material).

As a side effect, WP_Theme_JSON::resolve_variables() can now actually resolve these references (previously the constructed name didn't exist in the computed vars).

The editor is unaffected: the conversion runs when a config is sanitized for rendering; the global styles REST controller returns raw stored user data, so the client keeps seeing the same var:preset|… values it does today. Since references keep being stored with raw slugs (no data format change), nothing changes for existing content beyond the fixed rendering.

Core sync PR: WordPress/wordpress-develop#12656.

Testing Instructions

  1. In a theme's theme.json, register a font family whose slug changes when kebab-cased, e.g.:
    { "fontFamily": "N27, sans-serif", "name": "N27", "slug": "n27" }
  2. In the Site Editor, open Styles → Typography, assign that font (e.g. to Text or Headings), and save.
  3. View the front end: the computed font-family now references var(--wp--preset--font-family--n-27), matching the generated custom property, and the font applies. Without this PR the reference is --wp--preset--font-family--n27 and the font falls back. Note that with this fix, previously saved (broken) references heal without a re-save, since the fix is applied at render time.
  4. Regression check: confirm presets with ordinary kebab-safe slugs render unchanged.

PHP tests: npm run test:unit:php:base -- -- --filter WP_Theme_JSON_Gutenberg_Test (222 tests passing, including new coverage asserting the kebab-cased reference output for font family and spacing). The full PHP suite was compared against trunk: identical results (all pre-existing failures, none introduced).

@github-actions

Copy link
Copy Markdown

The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs. You can also manually ask me to refresh this list by adding the props-bot label.

If you're merging code through a pull request on GitHub, copy and paste the following into the bottom of the merge commit message.

Co-authored-by: jorgefilipecosta <jorgefilipecosta@git.wordpress.org>
Co-authored-by: oandregal <oandregal@git.wordpress.org>
Co-authored-by: fabiankaegy <fabiankaegy@git.wordpress.org>
Co-authored-by: justintadlock <greenshady@git.wordpress.org>
Co-authored-by: matiasbenedetto <mmaattiiaass@git.wordpress.org>

To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook.

@github-actions github-actions Bot added [Package] Editor /packages/editor [Package] Block editor /packages/block-editor labels Jul 22, 2026
@github-actions

github-actions Bot commented Jul 22, 2026

Copy link
Copy Markdown

Size Change: +250 B (0%)

Total Size: 7.75 MB

📦 View Changed
Filename Size Change
build/modules/lazy-editor/index.min.js 14.8 kB -1 B (-0.01%)
build/scripts/block-editor/index.min.js 428 kB +36 B (+0.01%)
build/scripts/components/index.min.js 273 kB +68 B (+0.02%)
build/scripts/edit-site/index.min.js 304 kB +33 B (+0.01%)
build/scripts/editor/index.min.js 501 kB +114 B (+0.02%)

compressed-size-action

@jorgefilipecosta
jorgefilipecosta force-pushed the fix/global-styles-preset-slug-kebab-case branch from 9af04a6 to a9bed26 Compare July 22, 2026 17:33
@github-actions github-actions Bot removed the [Package] Editor /packages/editor label Jul 22, 2026
@jorgefilipecosta
jorgefilipecosta force-pushed the fix/global-styles-preset-slug-kebab-case branch 2 times, most recently from 080b939 to f56e5a2 Compare July 22, 2026 18:20
@github-actions github-actions Bot added [Package] Editor /packages/editor and removed [Package] Block editor /packages/block-editor labels Jul 22, 2026
@jorgefilipecosta
jorgefilipecosta force-pushed the fix/global-styles-preset-slug-kebab-case branch from f56e5a2 to 8b57be5 Compare July 22, 2026 18:54
@jorgefilipecosta
jorgefilipecosta requested review from a team and ajitbohra as code owners July 22, 2026 18:54
@github-actions github-actions Bot added [Package] Components /packages/components [Package] Block editor /packages/block-editor labels Jul 22, 2026
@jorgefilipecosta
jorgefilipecosta force-pushed the fix/global-styles-preset-slug-kebab-case branch from 8b57be5 to 7660324 Compare July 22, 2026 19:42
@github-actions github-actions Bot removed [Package] Components /packages/components [Package] Editor /packages/editor [Package] Block editor /packages/block-editor labels Jul 22, 2026
@jorgefilipecosta jorgefilipecosta changed the title Global Styles: store kebab-cased preset slugs in preset variable references Global Styles: kebab-case preset slugs when converting references to custom properties Jul 22, 2026
@jorgefilipecosta jorgefilipecosta added the [Type] Bug An existing feature does not function as intended label Jul 23, 2026
…custom properties

WP_Theme_JSON_Gutenberg kebab-cases preset slugs when generating the
preset custom properties (get_settings_values_by_slug()), but
convert_custom_properties() converts stored references
(var:preset|font-family|n27) with a verbatim | to -- replacement. For a
slug that changes when kebab-cased, the reference
(--wp--preset--font-family--n27) never matches the generated custom
property (--wp--preset--font-family--n-27), so the preset does not apply
on the front end.

Kebab-case the slug of preset references in convert_custom_properties()
with the same _wp_to_kebab_case() used for the generated custom
properties. References that render correctly today are unchanged: they
only work when the slug is already a kebab-case fixed point, on which
_wp_to_kebab_case() is the identity.

Duotone references keep the raw slug: they are resolved by slug lookup in
WP_Duotone, not through the generated custom properties.
@jorgefilipecosta
jorgefilipecosta force-pushed the fix/global-styles-preset-slug-kebab-case branch from 01a4620 to 2ef3b1c Compare July 23, 2026 10:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

[Type] Bug An existing feature does not function as intended

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Font families with names containing numbers renders presets wrongly

1 participant