Skip to content

Editor: Add a background clip block support to facilitate text gradients - #13491

Open
aaronrobertshaw wants to merge 9 commits into
WordPress:trunkfrom
aaronrobertshaw:backport/77141-background-clip-support
Open

aaronrobertshaw wants to merge 9 commits into
WordPress:trunkfrom
aaronrobertshaw:backport/77141-background-clip-support

Conversation

@aaronrobertshaw

@aaronrobertshaw aaronrobertshaw commented Sep 11, 2026 •

Copy link
Copy Markdown

Backport of Gutenberg PRs WordPress/gutenberg#77141 and WordPress/gutenberg#77142

Trac ticket: https://core.trac.wordpress.org/ticket/66094

Adds a background.backgroundClip block support. A block can paint its background into border-box, padding-box, content-box, or the text itself, which gives a gradient text fill.

This PR backports:

  • the backgroundClip definition and value parser in WP_Style_Engine, with a VALID_BACKGROUND_CLIP_VALUES constant,
  • the setting, style and CSS property mapping in WP_Theme_JSON, with the vendor prefixed declarations,
  • background-clip and its vendor prefixed companions in the KSES allowlist,
  • no has-background class when the background is clipped to the text,
  • the escapes a breakpoint or pseudo state needs over an inherited text clip, in WP_Theme_JSON and the block states support,
  • the matching tests.

Box values only reset the fill color. Resetting -webkit-background-clip would 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

  1. Add this to a block theme's theme.json:
"styles": {
	"blocks": {
		"core/heading": {
			"background": {
				"gradient": "linear-gradient(to right,#ff0000,#0000ff)",
				"backgroundClip": "text"
			},
			"@mobile": {
				"color": {
					"text": "#00aa00"
				}
			}
		},
		"core/group": {
			"background": {
				"gradient": "linear-gradient(to right,#ff0000,#0000ff)",
				"backgroundClip": "content-box"
			}
		}
	}
}
  1. Load a page with a Heading and a Group. The global styles should contain:
:root :where(.wp-block-heading){background-image: linear-gradient(to right,#ff0000,#0000ff);background-clip: text;-webkit-background-clip: text;-webkit-text-fill-color: transparent;}
@media (width <= 480px){:root :where(.wp-block-heading){color: #00aa00;-webkit-text-fill-color: currentColor;}}
:root :where(.wp-block-group){background-image: linear-gradient(to right,#ff0000,#0000ff);background-clip: content-box;-webkit-text-fill-color: currentColor;}
  1. The heading shows the gradient on its letters, and plain green at 480px or narrower.
  2. Give the group padding and a thick dashed border. Its gradient stops at the inner edge of the padding.

Use of AI

AI assistance: Yes
Tool(s): Claude Code
Model(s): Claude Opus 5
Used for: the mechanical port

@github-actions

Copy link
Copy Markdown

Test using WordPress Playground

The 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

  • All changes will be lost when closing a tab with a Playground instance.
  • All changes will be lost when refreshing the page.
  • A fresh instance is created each time the link below is clicked.
  • Every time this pull request is updated, a new ZIP file containing all changes is created. If changes are not reflected in the Playground instance,
    it's possible that the most recent build failed, or has not completed. Check the list of workflow runs to be sure.

For more details about these limitations and more, check out the Limitations page in the WordPress Playground documentation.

Test this pull request with WordPress Playground.

@github-actions

github-actions Bot commented Sep 18, 2026 •

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.

Core Committers: Use this line as a base for the props when committing in SVN:

Props aaronrobertshaw, isabel_brison, andrewserong, peterwilsoncc, westonruter.

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

@aaronrobertshaw

Copy link
Copy Markdown
Author

FYI, things are evolving on the Gutenberg PR this backports. I'll mark this as in draft until that stabilizes.

@aaronrobertshaw
aaronrobertshaw marked this pull request as draft September 20, 2026 08:19
@aaronrobertshaw
aaronrobertshaw force-pushed the backport/77141-background-clip-support branch from 71ac410 to 1295d58 Compare October 1, 2026 07:45
@peterwilsoncc

Copy link
Copy Markdown
Contributor

@aaronrobertshaw Is this ready for review now that WordPress/gutenberg#77141 has merged?

@aaronrobertshaw

Copy link
Copy Markdown
Author

@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.

@aaronrobertshaw

Copy link
Copy Markdown
Author

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 tellthemachines left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 😅)

Comment thread src/wp-includes/style-engine/class-wp-style-engine.php
@peterwilsoncc

Copy link
Copy Markdown
Contributor

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 protected or replacing static:: with self:: will work, the phpstan issue because the calls will fail if someone extends WP_Theme_JSON. (Props @westonruter for allowing me to lazyweb this one.)

Comment thread src/wp-includes/class-wp-theme-json.php Outdated
Comment thread src/wp-includes/class-wp-theme-json.php Outdated
@aaronrobertshaw

Copy link
Copy Markdown
Author

Sorry for the delay on this one. I have addressed the feedback and believe this should be good for another review 🙏

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.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

State handling misses applicable clip styles and feature selectors, while invalid clip values can make text invisible.

5 open issues
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

Comment thread src/wp-includes/block-supports/states.php Outdated
Comment on lines +475 to +478
$base_clip = $base_style['background']['backgroundClip'] ?? '';
$declarations = array_merge(
$declarations,
wp_get_state_text_clip_escape( $style, is_string( $base_clip ) ? $base_clip : '' ),

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is rare and the editor matches it today, so I'll address it in a follow-up.

Comment on lines +785 to +788
wp_merge_state_style_objects(
$default_root_style,
$root_state_style
)

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is another rare combination, so I'll fix it in a follow-up with a test.

Comment on lines +4017 to +4018
unset( $base_path[ $index ] );
$layer = _wp_array_get( $tree, array_values( $base_path ) );

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same gap as the block instance case. I'll fix both in the same follow-up.

* so those properties are not output twice.
*/
$declarations = static::compute_style_properties( $node, $settings, null, $this->theme_json, $selector, $use_root_padding );
$declarations = self::get_state_declarations_with_text_clip_escapes( $declarations, $node, $base_styles );

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No core block can hit this today: only Heading and Paragraph support background clip, and neither uses a color feature selector. I'll include it in the follow-ups.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants