Loading
Issue #3631324: Generate more of the global stylesheet from the theme configuration
Summary
Ports more of WP_Theme_JSON::get_stylesheet() (Gutenberg 24.1) so themes can do in *.gutenberg.yml what a theme.json theme does in configuration.
getActiveThemeMergedDefinition()
- array_merge() of theme-support (a sub-theme replaced whole keys)
+ mergeThemeSupport() maps merge, lists replace (like theme.json)
- THEMENAME_gutenberg_definition_alter() of the default theme
+ THEMENAME_gutenberg_definition_alter() of the base themes, then the default theme
+ expandAppearanceTools() APPEARANCE_TOOLS_OPT_INS, root and blocks
PresetCssGenerator
- body { --wp--preset--* }
+ :root { --wp--preset--*, --wp--custom--* } (like WordPress: usable on <html>)
+ (the --wp--style--* layout variables stay on body)
+ custom → --wp--custom--* (root and per block)
+ fluid font size presets → clamp()
GlobalStylesGenerator
+ elements: :hover, :focus, :focus-visible, :active… of link and button
+ blocks: block.json selectors (feature selectors), states of core/button
+ and core/navigation-link, elements and variations (.is-style-x)
+ block gaps: spacing.blockGap of a block → .wp-block-x-is-layout-*
+ custom css of the root, elements, blocks and variations (& nesting)
+ root padding: --wp--style--root--padding-* and .has-global-padding
+ :root :where() on class selectors, like WordPress
styles[] in the editor
- presets, theme files, global styles
+ presets, global styles, theme files (same order as the frontend)Also:
gutenberg_get_global_settings(),gutenberg_get_global_styles()andDuotoneProcessorread the merged definition instead of the base theme's (or the active theme's) own one.- A base theme's
stylesfiles are resolved relative to the base theme, not the active sub-theme. - Non-core blocks get
.wp-block-<namespace>-<name>like WordPress (drupal/field→.wp-block-drupal-field, was.wp-block-field). - The preset CSS is generated once with the definition instead of on every request.
- README "Theme configuration" documents it.
Not ported: shared styles.variations, responsive states (@mobile…) in global styles, the fallback block gaps of themes without the block gap support (the .wp-container-* styles of LayoutProcessor apply the block's default gap) and the top/bottom root padding (WordPress puts it on .wp-site-blocks).
Evidence
- Before:
global-styles.spec.mjsfails on 4.0.x (expect(received).toMatchObject(expected): no custom properties, no merge, no block selector). After: it passes. It installs a test base theme and a sub-theme that changes one custom value, and checks in the canvas and on the frontend: the merged--wp--custom--*, a fluidclamp()font size, the Button radius on.wp-block-button__link, the outline variation, a link:hover, the root padding of a constrained Group, a block gap, root and block custom CSS, the expandedappearanceToolsand the base theme's stylesheet. - Unit tests (
tests/src/Unit/): the generated CSS of states, block selectors, variations, elements in blocks, block gaps, custom CSS, root padding, custom properties, fluid sizes, the merge andappearanceTools. - The full Playwright suite passes.
Merge Danger
Door: two-way
Blast Radius: theme styling
- Sub-themes that relied on replacing a whole
theme-supportkey of their base theme now get it merged. Lists still replace. - The preset variables move from
bodyto:root, like WordPress, so rules of<html>can use them. A theme that redefines them onbodystill wins; one that redefines them on:rootnow wins too, as its CSS comes later. The layout variables (--wp--style--*) stay onbody: the default editor styles that the canvas loads define the block gap there. - The alter hooks of base themes now run for their sub-themes.
- Global styles now come before the theme's editor stylesheets, as on the frontend, so a theme rule of the same specificity now wins in the editor too.
- Block styles of non-core blocks change selector (see above).
Edited by Marco Fernandes