Skip to content

Commit 24950cb

Browse files
Button: Add background image, size, and gradient support (#83950)
* Button: Add background image, size, and gradient support * Button: Update gradient e2e expectations for background.gradient storage With background.gradient support, the Background panel stores both preset and custom gradients in style.background.gradient instead of the legacy gradient attribute or style.color.gradient. Background support renders on the server, so the saved markup no longer carries the gradient class or inline style. Check the gradient in the editor canvas instead, and cover preset gradients in the server render test. Co-authored-by: aaronrobertshaw <aaronrobertshaw@git.wordpress.org> Co-authored-by: andrewserong <andrewserong@git.wordpress.org>
1 parent c7c3880 commit 24950cb

7 files changed

Lines changed: 134 additions & 5 deletions

File tree

‎docs/reference-guides/core-blocks/README.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ Prompt visitors to take action with a button-style link.
111111
- **Name:** [core/button](https://developer.wordpress.org/block-editor/reference-guides/core-blocks/core-blocks-design/core-block-button/)
112112
- **Category:** [design](https://developer.wordpress.org/block-editor/reference-guides/core-blocks/core-blocks-design/)
113113
- **Parent:** core/buttons
114-
- **Supports:** anchor, color (background, gradients, text), dimensions (width), interactivity (clientNavigation), shadow, spacing (padding), splitting, typography (fontSize, lineHeight, textAlign), ~~alignWide~~, ~~align~~, ~~reusable~~
114+
- **Supports:** anchor, background (backgroundImage, backgroundSize, gradient), color (background, gradients, text), dimensions (width), interactivity (clientNavigation), shadow, spacing (padding), splitting, typography (fontSize, lineHeight, textAlign), ~~alignWide~~, ~~align~~, ~~reusable~~
115115
- **Attributes:** backgroundColor, gradient, linkTarget, placeholder, rel, tagName, text, textColor, title, type, url
116116

117117
## Buttons

‎packages/block-library/src/button/README.md‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,10 @@ _Defined via the [`supports`](https://developer.wordpress.org/block-editor/refer
4040
- [`splitting`](https://developer.wordpress.org/block-editor/reference-guides/block-api/block-supports/#splitting): `true`
4141
- [`align`](https://developer.wordpress.org/block-editor/reference-guides/block-api/block-supports/#align): `false`
4242
- [`alignWide`](https://developer.wordpress.org/block-editor/reference-guides/block-api/block-supports/#alignwide): `false`
43+
- [`background`](https://developer.wordpress.org/block-editor/reference-guides/block-api/block-supports/#background):
44+
- `backgroundImage`: `true`
45+
- `backgroundSize`: `true`
46+
- `gradient`: `true`
4347
- [`color`](https://developer.wordpress.org/block-editor/reference-guides/block-api/block-supports/#color):
4448
- [`gradients`](https://developer.wordpress.org/block-editor/reference-guides/block-api/block-supports/#color-gradients): `true`
4549
- [`dimensions`](https://developer.wordpress.org/block-editor/reference-guides/block-api/block-supports/#dimensions):

‎packages/block-library/src/button/block.json‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,12 @@
7070
"splitting": true,
7171
"align": false,
7272
"alignWide": false,
73+
"background": {
74+
"backgroundImage": true,
75+
"backgroundSize": true,
76+
"gradient": true,
77+
"__experimentalSkipSerialization": true
78+
},
7379
"color": {
7480
"__experimentalSkipSerialization": true,
7581
"gradients": true,

‎packages/block-library/src/button/edit.jsx‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import {
1616
LinkControl,
1717
__experimentalUseBorderProps as useBorderProps,
1818
__experimentalUseColorProps as useColorProps,
19+
useBackgroundProps,
1920
__experimentalGetSpacingClassesAndStyles as useSpacingProps,
2021
__experimentalGetShadowClassesAndStyles as useShadowProps,
2122
__experimentalGetDimensionsClassesAndStyles as useDimensionsProps,
@@ -166,6 +167,7 @@ function ButtonEdit( props ) {
166167
const colorProps = useColorProps( attributes );
167168
const spacingProps = useSpacingProps( attributes );
168169
const shadowProps = useShadowProps( attributes );
170+
const backgroundProps = useBackgroundProps( attributes );
169171
const dimensionsProps = useDimensionsProps( attributes );
170172
const ref = useRef();
171173
const richTextRef = useRef();
@@ -348,6 +350,7 @@ function ButtonEdit( props ) {
348350
className,
349351
'wp-block-button__link',
350352
colorProps.className,
353+
backgroundProps.className,
351354
borderProps.className,
352355
typographyProps.className,
353356
{
@@ -362,6 +365,7 @@ function ButtonEdit( props ) {
362365
style={ {
363366
...borderProps.style,
364367
...colorProps.style,
368+
...backgroundProps.style,
365369
...spacingProps.style,
366370
...shadowProps.style,
367371
...typographyProps.style,

‎packages/block-library/src/button/index.php‎

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,53 @@ function render_block_core_button( $attributes, $content ) {
6060
return '';
6161
}
6262

63+
// Background skips serialization, so apply it to the link like color.
64+
$background = $attributes['style']['background'] ?? null;
65+
66+
if ( is_array( $background ) ) {
67+
$background_styles = array(
68+
'backgroundImage' => $background['backgroundImage'] ?? null,
69+
'backgroundSize' => $background['backgroundSize'] ?? null,
70+
'backgroundPosition' => $background['backgroundPosition'] ?? null,
71+
'backgroundRepeat' => $background['backgroundRepeat'] ?? null,
72+
'backgroundAttachment' => $background['backgroundAttachment'] ?? null,
73+
'gradient' => $background['gradient'] ?? null,
74+
);
75+
76+
// Mirror the background block support defaults.
77+
if ( ! empty( $background_styles['backgroundImage'] ) ) {
78+
$background_styles['backgroundSize'] = $background_styles['backgroundSize'] ?? 'cover';
79+
if ( 'contain' === $background_styles['backgroundSize'] && ! $background_styles['backgroundPosition'] ) {
80+
$background_styles['backgroundPosition'] = '50% 50%';
81+
}
82+
}
83+
84+
$styles = wp_style_engine_get_styles( array( 'background' => $background_styles ) );
85+
86+
if ( ! empty( $styles['css'] ) ) {
87+
$processor = new WP_HTML_Tag_Processor( $content );
88+
while ( $processor->next_tag() ) {
89+
if ( $tag !== $processor->get_tag() ) {
90+
continue;
91+
}
92+
93+
$existing_style = $processor->get_attribute( 'style' );
94+
if ( is_string( $existing_style ) && '' !== $existing_style ) {
95+
$separator = str_ends_with( $existing_style, ';' ) ? '' : ';';
96+
$processor->set_attribute( 'style', $existing_style . $separator . $styles['css'] );
97+
} else {
98+
$processor->set_attribute( 'style', $styles['css'] );
99+
}
100+
101+
if ( ! empty( $background_styles['backgroundImage'] ) || ! empty( $background_styles['gradient'] ) ) {
102+
$processor->add_class( 'has-background' );
103+
}
104+
break;
105+
}
106+
$content = $processor->get_updated_html();
107+
}
108+
}
109+
63110
$width = $attributes['style']['dimensions']['width'] ?? null;
64111

65112
if ( is_string( $width ) && '' !== $width ) {

‎phpunit/blocks/render-block-button-test.php‎

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,4 +136,67 @@ public function test_custom_percentage_width_adds_generic_class_without_legacy()
136136
$this->assertStringNotContainsString( 'wp-block-button__width-33', $result );
137137
$this->assertStringContainsString( '--wp--block-button--width: 33;', $result );
138138
}
139+
140+
/**
141+
* @covers ::gutenberg_render_block_core_button
142+
*/
143+
public function test_background_image_applies_to_link() {
144+
$attributes = array(
145+
'style' => array(
146+
'background' => array(
147+
'backgroundImage' => array(
148+
'url' => 'https://example.com/image.jpg',
149+
),
150+
),
151+
),
152+
);
153+
154+
$result = gutenberg_render_block_core_button( $attributes, self::$button_content );
155+
$processor = new WP_HTML_Tag_Processor( $result );
156+
$processor->next_tag( 'a' );
157+
158+
$this->assertSame( "background-image:url('https://example.com/image.jpg');background-size:cover;", $processor->get_attribute( 'style' ) );
159+
$this->assertTrue( $processor->has_class( 'has-background' ) );
160+
}
161+
162+
/**
163+
* @covers ::gutenberg_render_block_core_button
164+
*/
165+
public function test_background_gradient_appends_to_existing_link_style() {
166+
$content = '<div class="wp-block-button"><a class="wp-block-button__link wp-element-button" style="color:#fff">Click me</a></div>';
167+
$attributes = array(
168+
'style' => array(
169+
'background' => array(
170+
'gradient' => 'linear-gradient(red, blue)',
171+
),
172+
),
173+
);
174+
175+
$result = gutenberg_render_block_core_button( $attributes, $content );
176+
177+
$this->assertSame(
178+
'<div class="wp-block-button"><a class="wp-block-button__link wp-element-button has-background" style="color:#fff;background-image:linear-gradient(red, blue);">Click me</a></div>',
179+
$result
180+
);
181+
}
182+
183+
/**
184+
* @covers ::gutenberg_render_block_core_button
185+
*/
186+
public function test_background_gradient_preset_applies_to_link() {
187+
$attributes = array(
188+
'style' => array(
189+
'background' => array(
190+
'gradient' => 'var:preset|gradient|purple-to-yellow',
191+
),
192+
),
193+
);
194+
195+
$result = gutenberg_render_block_core_button( $attributes, self::$button_content );
196+
$processor = new WP_HTML_Tag_Processor( $result );
197+
$processor->next_tag( 'a' );
198+
199+
$this->assertSame( 'background-image:var(--wp--preset--gradient--purple-to-yellow);', $processor->get_attribute( 'style' ) );
200+
$this->assertTrue( $processor->has_class( 'has-background' ) );
201+
}
139202
}

‎test/e2e/specs/editor/blocks/buttons.spec.js‎

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -392,12 +392,17 @@ test.describe( 'Buttons', () => {
392392
.getByRole( 'option', { name: 'Gradient: Purple to yellow' } )
393393
.click();
394394

395+
// Background support renders on the server, so the gradient is absent from the saved markup.
396+
await expect(
397+
editor.canvas.locator( '.wp-block-button__link' )
398+
).toHaveCSS( 'background-image', /gradient/ );
399+
395400
// Check the content.
396401
const content = await editor.getEditedPostContent();
397402
expect( content ).toBe(
398403
`<!-- wp:buttons -->
399-
<div class=\"wp-block-buttons\"><!-- wp:button {\"gradient\":\"purple-to-yellow\"} -->
400-
<div class=\"wp-block-button\"><a class=\"wp-block-button__link has-purple-to-yellow-gradient-background has-background wp-element-button\">Content</a></div>
404+
<div class=\"wp-block-buttons\"><!-- wp:button {\"style\":{\"background\":{\"gradient\":\"var:preset|gradient|purple-to-yellow\"}}} -->
405+
<div class=\"wp-block-button\"><a class=\"wp-block-button__link wp-element-button\">Content</a></div>
401406
<!-- /wp:button --></div>
402407
<!-- /wp:buttons -->`
403408
);
@@ -437,8 +442,8 @@ test.describe( 'Buttons', () => {
437442
const content = await editor.getEditedPostContent();
438443
expect( content ).toBe(
439444
`<!-- wp:buttons -->
440-
<div class=\"wp-block-buttons\"><!-- wp:button {\"style\":{\"color\":{\"gradient\":\"linear-gradient(135deg,rgb(255,0,0) 0%,rgb(0,255,0) 100%)\"}}} -->
441-
<div class=\"wp-block-button\"><a class=\"wp-block-button__link has-background wp-element-button\" style=\"background:linear-gradient(135deg,rgb(255,0,0) 0%,rgb(0,255,0) 100%)\">Content</a></div>
445+
<div class=\"wp-block-buttons\"><!-- wp:button {\"style\":{\"background\":{\"gradient\":\"linear-gradient(135deg,rgb(255,0,0) 0%,rgb(0,255,0) 100%)\"}}} -->
446+
<div class=\"wp-block-button\"><a class=\"wp-block-button__link wp-element-button\">Content</a></div>
442447
<!-- /wp:button --></div>
443448
<!-- /wp:buttons -->`
444449
);

0 commit comments

Comments
 (0)