Repository navigation
Editor: Add a background clip block support to facilitate text gradients - #13491
aaronrobertshaw wants to merge 13 commits into
Conversation
Test using WordPress PlaygroundThe changes in this pull request can previewed and tested using a WordPress Playground instance. WordPress Playground is an experimental project that creates a full WordPress instance entirely within the browser. Some things to be aware of
For more details about these limitations and more, check out the Limitations page in the WordPress Playground documentation. |
582fe2b to
71ac410
Compare
|
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 Core Committers: Use this line as a base for the props when committing in SVN: To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook. |
|
FYI, things are evolving on the Gutenberg PR this backports. I'll mark this as in draft until that stabilizes. |
71ac410 to
1295d58
Compare
|
@aaronrobertshaw Is this ready for review now that WordPress/gutenberg#77141 has merged? |
|
@peterwilsoncc not quite, there is a closely related PR that has changes that might be best backported in this single PR: WordPress/gutenberg#77142. That Gutenberg PR has a few more changes in the works that might need backporting too. So I'll update as I can and flag this ready once it has the full set of updates. |
1295d58 to
6d8ee2a
Compare
6d8ee2a to
4ec37c1
Compare
8ed54ed to
f0dbb85
Compare
|
Both WordPress/gutenberg#77141 and WordPress/gutenberg#77142 have now landed in Gutenberg. This backport has been updated to cover the latest from both PRs and should be ready for an initial review. |
tellthemachines
left a comment
There was a problem hiding this comment.
Other than the style engine class changes this LGTM as it's accurate in comparison with the two source PRs.
Not sure about the warnings on the theme.json class though (might be more helpful if these warnings were consistent between the two repos 😅)
Either changing the visibility of the methods to |
|
Sorry for the delay on this one. I have addressed the feedback and believe this should be good for another review 🙏 |
f095d62 to
210bd28
Compare
There was a problem hiding this comment.
🟡 Changes recommended
State handling misses applicable clip styles and feature selectors, while invalid clip values can make text invisible.
5 open issues
Validate clip values before clearing images or restoring fills · New Resolve global clip styles before layering instance styles · New Include default pseudo-state when resolving breakpoint clip styles · New Include default pseudo-state in responsive cascade layers · New Apply fill escapes to feature-selector declarations · New
What changed in this PR
Backports background clipping support into WordPress’s server-side styling pipeline, enabling text gradients and box clipping.
Changes:
- Adds clip parsing, theme.json mappings, and allowed CSS properties.
- Adjusts background classes and state-specific text-fill resets.
- Adds rendering and stylesheet regression tests.
| File | Description |
|---|---|
| tests/phpunit/tests/theme/wpThemeJson.php | Tests responsive and pseudo-state clip handling. |
| tests/phpunit/tests/style-engine/styleEngine.php | Tests clip declarations and invalid values. |
| tests/phpunit/tests/block-supports/wpRenderBackgroundSupport.php | Tests clipping output and background classes. |
| tests/phpunit/tests/block-supports/states.php | Tests state escapes and fill resets. |
| tests/phpunit/tests/block-supports/colors.php | Tests background classes with clipping. |
| src/wp-includes/style-engine/class-wp-style-engine.php | Adds clip validation and CSS generation. |
| src/wp-includes/kses.php | Allows clipping and text-fill properties. |
| src/wp-includes/class-wp-theme-json.php | Generates clip styles and state escapes. |
| src/wp-includes/block-supports/states.php | Adds state layering and reset helpers. |
| src/wp-includes/block-supports/colors.php | Suppresses background classes for clipped colors. |
| src/wp-includes/block-supports/background.php | Renders clipping and adjusts background classes. |
Review effort: Balanced
Adds a background.backgroundClip block support, so a block can set which box its background is painted into: border-box, padding-box, content-box, or the text itself. Clipping to the text is what gives blocks a gradient text fill. Registers the property in the style engine and theme.json, allows the declarations through KSES, and skips the has-background class when the background is clipped to the text. Props aaronrobertshaw. See #66094.
Backports the PHP from Gutenberg PR 77142. A breakpoint or pseudo state layered over a text clip now unsets the inherited gradient when it sets a box clip, and restores the text fill when it only sets a text color. See #66094.
…radient Backports the PHP from Gutenberg PR 77142. A breakpoint or hover text color on a block that supports the background clip now fills the letters again even when the text gradient comes from global styles. See #66094.
Backports the PHP from Gutenberg PR 77142. A background color on a block that clips its background to the text is clipped to the letters too, so it no longer adds has-background and the padding that comes with it. See #66094.
…lter_attr(). The 7.2.0 line for background-clip sat between the 7.1.0 line and its continuation, so the 7.1.0 transform and clip-path notes read as 7.2.0 changes. It now continues the existing 7.2.0 entry. See #66094.
…orts and theme.json.
dc95657 to
f103750
Compare
|
Thanks @westonruter, I've addressed your remaining feedback and rebased on the latest trunk. I think this is ready for a final review. Would you mind taking another look when you get a chance? |
andrewserong
left a comment
There was a problem hiding this comment.
For what it's worth, this is testing well for me and looks like a faithful backport of the already merged Gutenberg PRs, and the addressed feedback appears to have been carefully captured in the open GB PR (WordPress/gutenberg#85057)
Things I tested included:
- The overall feature and its different values
unseting for pseudo and responsive states- All seemed to be working nicely as far as I can tell:
Left a tiny nit re: a docblock comment. I was vaguely wondering if it's possible to consolidate any of the wpThemeJson.php tests as they're fairly verbose but not a blocker.
IMO this is in good shape to land for Beta 1, and as mentioned there are ideas for smaller follow-ups that could land during the beta cycle.
LGTM!
| * Added support for `dimensions.width` and `dimensions.height`. | ||
| * Added support for `typography.textIndent`. | ||
| * @since 7.1.0 Added `viewport` property. | ||
| * @since 7.2.0 Added `background.backgroundClip` property. |
There was a problem hiding this comment.
Tiny nit: I think this needs to move a line below, or it looks like background.gradient, dimensions.minWidth etc made it in for 7.2 instead of 7.1
westonruter
left a comment
There was a problem hiding this comment.
I'm not super familiar with the style engine code, so I don't want to hold this up.
I will note there remains improvements to static analysis that may land later.
------ -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Line src/wp-includes/block-supports/colors.php
------ -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
141 Cannot access offset 'background' on mixed.
🪪 offsetAccess.nonOffsetAccessible
141 Cannot access offset 'backgroundClip' on mixed.
🪪 offsetAccess.nonOffsetAccessible
------ -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
------ -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Line src/wp-includes/block-supports/states.php
------ -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
168 Parameter #1 $target of function wp_merge_state_style_objects expects array<string, mixed>, array<mixed, mixed> given.
🪪 argument.type
168 Parameter #2 $source of function wp_merge_state_style_objects expects array<string, mixed>, array<mixed, mixed> given.
🪪 argument.type
185 Cannot access offset 'gradient' on mixed.
🪪 offsetAccess.nonOffsetAccessible
186 Cannot access offset 'backgroundImage' on mixed.
🪪 offsetAccess.nonOffsetAccessible
187 Cannot access offset 'gradient' on mixed.
🪪 offsetAccess.nonOffsetAccessible
204 Cannot access offset 'backgroundClip' on mixed.
🪪 offsetAccess.nonOffsetAccessible
230 Cannot access offset 'backgroundClip' on mixed.
🪪 offsetAccess.nonOffsetAccessible
234 Cannot access offset 'text' on mixed.
🪪 offsetAccess.nonOffsetAccessible
467 Function wp_add_block_state_style_rule() has no return type specified.
🪪 missingType.return
467 Function wp_add_block_state_style_rule() has parameter $css_rules with no value type specified in iterable type array.
💡 See: https://phpstan.org/blog/solving-phpstan-no-value-type-specified-in-iterable-type
🪪 missingType.iterableValue
486 Cannot access offset 'backgroundClip' on mixed.
🪪 offsetAccess.nonOffsetAccessible
489 Parameter #1 $state_style of function wp_get_state_text_clip_escape expects array<string, mixed>, array given.
🪪 argument.type
490 Parameter #1 $state_style of function wp_get_state_text_fill_reset expects array<string, mixed>, array given.
🪪 argument.type
520 Function wp_get_block_state_style_rules() return type has no value type specified in iterable type array.
💡 See: https://phpstan.org/blog/solving-phpstan-no-value-type-specified-in-iterable-type
🪪 missingType.iterableValue
707 Parameter #4 $base_style of function wp_get_block_state_style_rules expects array<string, mixed>|null, array given.
🪪 argument.type
728 Parameter #3 $rules_group of function wp_get_block_state_style_rules expects string|null, mixed given.
🪪 argument.type
729 Parameter #4 $base_style of function wp_get_block_state_style_rules expects array<string, mixed>|null, array given.
🪪 argument.type
795 Parameter #3 $rules_group of function wp_get_block_state_style_rules expects string|null, mixed given.
🪪 argument.type
797 Parameter #1 $target of function wp_merge_state_style_objects expects array<string, mixed>, array given.
🪪 argument.type
798 Parameter #2 $source of function wp_merge_state_style_objects expects array<string, mixed>, array given.
🪪 argument.type
------ -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
------ -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Line src/wp-includes/class-wp-theme-json.php
------ -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
1012 Parameter #2 $path of function _wp_array_get expects array, mixed given.
🪪 argument.type
1039 Parameter #1 $declarations of static method WP_Theme_JSON::get_state_declarations_with_text_clip_escapes() expects list<array{name: non-falsy-string, value: bool|float|int|string}>, array given.
💡 array<int|string, mixed> might not be a list.
🪪 argument.type
1039 Parameter #2 $state_style of static method WP_Theme_JSON::get_state_declarations_with_text_clip_escapes() expects array<string, mixed>, mixed given.
🪪 argument.type
3983 Parameter #2 ...$args of function array_merge expects array, mixed given.
🪪 argument.type
3987 Parameter #2 ...$args of function array_merge expects array, mixed given.
🪪 argument.type
3991 Parameter #2 ...$args of function array_merge expects array, mixed given.
🪪 argument.type
3994 Method WP_Theme_JSON::get_style_state_keys() should return list<non-falsy-string> but returns list.
🪪 return.type
3994 Parameter #1 $array of function array_unique expects an array of values castable to string, array given.
🪪 argument.type
4009 Method WP_Theme_JSON::get_state_base_styles() return type has no value type specified in iterable type array.
💡 See: https://phpstan.org/blog/solving-phpstan-no-value-type-specified-in-iterable-type
🪪 missingType.iterableValue
4042 Method WP_Theme_JSON::get_state_declarations_with_text_clip_escapes() has parameter $base_styles with no value type specified in iterable type array.
💡 See: https://phpstan.org/blog/solving-phpstan-no-value-type-specified-in-iterable-type
🪪 missingType.iterableValue
4045 Cannot access offset 'backgroundClip' on mixed.
🪪 offsetAccess.nonOffsetAccessible
4206 Parameter #1 $declarations of static method WP_Theme_JSON::get_state_declarations_with_text_clip_escapes() expects list<array{name: non-falsy-string, value: bool|float|int|string}>, array given.
💡 array<int|string, mixed> might not be a list.
🪪 argument.type
4207 Parameter #2 $state_style of static method WP_Theme_JSON::get_state_declarations_with_text_clip_escapes() expects array<string, mixed>, array given.
🪪 argument.type
4334 Parameter #1 $path of static method WP_Theme_JSON::get_state_base_styles() expects array<string>, array given.
🪪 argument.type
4334 Parameter #2 $tree of static method WP_Theme_JSON::get_state_base_styles() expects array<string, mixed>, array given.
🪪 argument.type
4334 Parameter #3 $settings of static method WP_Theme_JSON::get_state_base_styles() expects array<string, mixed>, mixed given.
🪪 argument.type
4342 Parameter #1 $declarations of static method WP_Theme_JSON::get_state_declarations_with_text_clip_escapes() expects list<array{name: non-falsy-string, value: bool|float|int|string}>, array given.
💡 array<int|string, mixed> might not be a list.
🪪 argument.type
4343 Parameter #2 $state_style of static method WP_Theme_JSON::get_state_declarations_with_text_clip_escapes() expects array<string, mixed>, mixed given.
🪪 argument.type
4343 Possibly invalid array key type mixed.
🪪 offsetAccess.invalidOffset
4353 Parameter #1 $declarations of static method WP_Theme_JSON::get_state_declarations_with_text_clip_escapes() expects list<array{name: non-falsy-string, value: bool|float|int|string}>, array given.
💡 array<int|string, mixed> might not be a list.
🪪 argument.type
4353 Parameter #2 $state_style of static method WP_Theme_JSON::get_state_declarations_with_text_clip_escapes() expects array<string, mixed>, array given.
🪪 argument.type
------ -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
------ -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Line src/wp-includes/style-engine/class-wp-style-engine.php
------ -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
798 Method WP_Style_Engine::get_background_clip_css_declarations() has parameter $style_definition with no value type specified in iterable type array.
💡 See: https://phpstan.org/blog/solving-phpstan-no-value-type-specified-in-iterable-type
🪪 missingType.iterableValue
------ -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
[ERROR] Found 44 errors on changed lines (base: trunk)

Backport of Gutenberg PRs WordPress/gutenberg#77141 and WordPress/gutenberg#77142
Trac ticket: https://core.trac.wordpress.org/ticket/66094
Adds a
background.backgroundClipblock support. A block can paint its background intoborder-box,padding-box,content-box, or the text itself, which gives a gradient text fill.This PR backports:
backgroundClipdefinition and value parser inWP_Style_Engine, with aVALID_BACKGROUND_CLIP_VALUESconstant,WP_Theme_JSON, with the vendor prefixed declarations,background-clipand its vendor prefixed companions in the KSES allowlist,has-backgroundclass when the background is clipped to the text,WP_Theme_JSONand the block states support,Box values only reset the fill color. Resetting
-webkit-background-clipwould discard the clip in Chromium.Without the escapes, a state over a text clip keeps the gradient in its letters.
The editor controls and the Heading and Paragraph opt-ins arrive with the next Gutenberg package update. Until then, the Paragraph breakpoint tests keep their current expectations, and a test block covers the text fill reset.
Testing instructions
theme.json:Use of AI
AI assistance: Yes
Tool(s): Claude Code
Model(s): Claude Opus 5
Used for: the mechanical port