Skip to content

Commit 6b190c6

Browse files
committed
Block Supports: Add background gradient support that can combine with background image
Adds `background.gradient` as a new block support, enabling blocks to combine a background gradient with a background image via comma-separated `background-image` CSS values (e.g., `background-image: linear-gradient(...), url(...)`). Before, the only way to apply a gradient is through `color.gradient`, which renders as a `background` CSS shorthand and conflicts with background image properties. By introducing `background.gradient` (stored at `style.background.gradient`), gradients become part of the background style group, allowing the style engine to combine gradient and image values without conflict. Props aaronrobertshaw, ramonopoly, wildworks. Fixes #64974. git-svn-id: https://develop.svn.wordpress.org/trunk@62718 602fd350-edb4-49c9-b593-d223f7449a82
1 parent 068b578 commit 6b190c6

10 files changed

Lines changed: 649 additions & 27 deletions

File tree

src/wp-includes/block-supports/background.php

Lines changed: 32 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ function wp_register_background_support( $block_type ) {
4343
* @since 6.5.0 Added support for `backgroundPosition` and `backgroundRepeat` output.
4444
* @since 6.6.0 Removed requirement for `backgroundImage.source`. A file/url is the default.
4545
* @since 6.7.0 Added support for `backgroundAttachment` output.
46+
* @since 7.1.0 Added support for `background.gradient` output.
4647
*
4748
* @access private
4849
*
@@ -51,34 +52,49 @@ function wp_register_background_support( $block_type ) {
5152
* @return string Filtered block content.
5253
*/
5354
function wp_render_background_support( $block_content, $block ) {
54-
$block_type = WP_Block_Type_Registry::get_instance()->get_registered( $block['blockName'] );
55-
$block_attributes = ( isset( $block['attrs'] ) && is_array( $block['attrs'] ) ) ? $block['attrs'] : array();
56-
$has_background_image_support = block_has_support( $block_type, array( 'background', 'backgroundImage' ), false );
55+
$block_type = WP_Block_Type_Registry::get_instance()->get_registered( $block['blockName'] );
56+
$block_attributes = ( isset( $block['attrs'] ) && is_array( $block['attrs'] ) ) ? $block['attrs'] : array();
57+
$has_background_image_support = block_has_support( $block_type, array( 'background', 'backgroundImage' ), false );
58+
$has_background_gradient_support = block_has_support( $block_type, array( 'background', 'gradient' ), false );
5759

5860
if (
59-
! $has_background_image_support ||
60-
wp_should_skip_block_supports_serialization( $block_type, 'background', 'backgroundImage' ) ||
61+
( ! $has_background_image_support && ! $has_background_gradient_support ) ||
6162
! isset( $block_attributes['style']['background'] )
6263
) {
6364
return $block_content;
6465
}
6566

66-
$background_styles = array();
67-
$background_styles['backgroundImage'] = $block_attributes['style']['background']['backgroundImage'] ?? null;
68-
$background_styles['backgroundSize'] = $block_attributes['style']['background']['backgroundSize'] ?? null;
69-
$background_styles['backgroundPosition'] = $block_attributes['style']['background']['backgroundPosition'] ?? null;
70-
$background_styles['backgroundRepeat'] = $block_attributes['style']['background']['backgroundRepeat'] ?? null;
71-
$background_styles['backgroundAttachment'] = $block_attributes['style']['background']['backgroundAttachment'] ?? null;
67+
// Check serialization skip for each feature individually.
68+
$skip_background_image = ! $has_background_image_support || wp_should_skip_block_supports_serialization( $block_type, 'background', 'backgroundImage' );
69+
$skip_background_gradient = ! $has_background_gradient_support || wp_should_skip_block_supports_serialization( $block_type, 'background', 'gradient' );
7270

73-
if ( ! empty( $background_styles['backgroundImage'] ) ) {
74-
$background_styles['backgroundSize'] = $background_styles['backgroundSize'] ?? 'cover';
71+
if ( $skip_background_image && $skip_background_gradient ) {
72+
return $block_content;
73+
}
74+
75+
$background_styles = array();
76+
77+
if ( ! $skip_background_image ) {
78+
$background_styles['backgroundImage'] = $block_attributes['style']['background']['backgroundImage'] ?? null;
79+
$background_styles['backgroundSize'] = $block_attributes['style']['background']['backgroundSize'] ?? null;
80+
$background_styles['backgroundPosition'] = $block_attributes['style']['background']['backgroundPosition'] ?? null;
81+
$background_styles['backgroundRepeat'] = $block_attributes['style']['background']['backgroundRepeat'] ?? null;
82+
$background_styles['backgroundAttachment'] = $block_attributes['style']['background']['backgroundAttachment'] ?? null;
7583

76-
// If the background size is set to `contain` and no position is set, set the position to `center`.
77-
if ( 'contain' === $background_styles['backgroundSize'] && ! $background_styles['backgroundPosition'] ) {
78-
$background_styles['backgroundPosition'] = '50% 50%';
84+
if ( ! empty( $background_styles['backgroundImage'] ) ) {
85+
$background_styles['backgroundSize'] = $background_styles['backgroundSize'] ?? 'cover';
86+
87+
// If the background size is set to `contain` and no position is set, set the position to `center`.
88+
if ( 'contain' === $background_styles['backgroundSize'] && ! $background_styles['backgroundPosition'] ) {
89+
$background_styles['backgroundPosition'] = '50% 50%';
90+
}
7991
}
8092
}
8193

94+
if ( ! $skip_background_gradient ) {
95+
$background_styles['gradient'] = $block_attributes['style']['background']['gradient'] ?? null;
96+
}
97+
8298
$styles = wp_style_engine_get_styles( array( 'background' => $background_styles ) );
8399

84100
if ( ! empty( $styles['css'] ) ) {

src/wp-includes/block-supports/colors.php

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ function wp_register_colors_support( $block_type ) {
7373
*
7474
* @since 5.6.0
7575
* @since 6.1.0 Implemented the style engine to generate CSS and classnames.
76+
* @since 7.1.0 Suppresses color.gradient when background.gradient is supported and set.
7677
* @access private
7778
*
7879
* @param WP_Block_Type $block_type Block type.
@@ -114,7 +115,17 @@ function wp_apply_colors_support( $block_type, $block_attributes ) {
114115
}
115116

116117
// Gradients.
117-
if ( $has_gradients_support && ! wp_should_skip_block_supports_serialization( $block_type, 'color', 'gradients' ) ) {
118+
// Suppress color.gradient CSS when background.gradient is supported and
119+
// explicitly set. background.php owns CSS generation in that case, and
120+
// emitting the background shorthand here would conflict with it.
121+
$has_background_gradient_support = block_has_support( $block_type, array( 'background', 'gradient' ), false );
122+
$has_background_gradient_value = ! empty( $block_attributes['style']['background']['gradient'] );
123+
124+
if (
125+
$has_gradients_support &&
126+
! wp_should_skip_block_supports_serialization( $block_type, 'color', 'gradients' ) &&
127+
! ( $has_background_gradient_support && $has_background_gradient_value )
128+
) {
118129
$preset_gradient_color = array_key_exists( 'gradient', $block_attributes ) ? "var:preset|gradient|{$block_attributes['gradient']}" : null;
119130
$custom_gradient_color = $block_attributes['style']['color']['gradient'] ?? null;
120131
$color_block_styles['gradient'] = $preset_gradient_color ? $preset_gradient_color : $custom_gradient_color;

src/wp-includes/class-wp-theme-json.php

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -330,6 +330,7 @@ class WP_Theme_JSON {
330330
*
331331
* @since 6.2.0
332332
* @since 6.6.0 Added background-image properties.
333+
* @since 7.1.0 Added `background.gradient` to `background-image` paths.
333334
* @var array
334335
*/
335336
const INDIRECT_PROPERTIES_METADATA = array(
@@ -348,6 +349,7 @@ class WP_Theme_JSON {
348349
),
349350
'background-image' => array(
350351
array( 'background', 'backgroundImage', 'url' ),
352+
array( 'background', 'gradient' ),
351353
),
352354
);
353355

@@ -413,6 +415,7 @@ class WP_Theme_JSON {
413415
* Added support for `dimensions.width` and `dimensions.height`.
414416
* Added support for `typography.textIndent`.
415417
* @since 7.1.0 Added `viewport` property.
418+
* Added support for `background.gradient`.
416419
* @var array
417420
*/
418421
const VALID_SETTINGS = array(
@@ -421,6 +424,7 @@ class WP_Theme_JSON {
421424
'background' => array(
422425
'backgroundImage' => null,
423426
'backgroundSize' => null,
427+
'gradient' => null,
424428
),
425429
'border' => array(
426430
'color' => null,
@@ -554,6 +558,7 @@ class WP_Theme_JSON {
554558
* @since 6.5.0 Added support for `dimensions.aspectRatio`.
555559
* @since 6.6.0 Added `background` sub properties to top-level only.
556560
* @since 7.0.0 Added support for `dimensions.width` and `dimensions.height`.
561+
* @since 7.1.0 Added `background.gradient`.
557562
* @var array
558563
*/
559564
const VALID_STYLES = array(
@@ -563,6 +568,7 @@ class WP_Theme_JSON {
563568
'backgroundRepeat' => null,
564569
'backgroundSize' => null,
565570
'backgroundAttachment' => null,
571+
'gradient' => null,
566572
),
567573
'border' => array(
568574
'color' => null,
@@ -1021,11 +1027,13 @@ public static function get_element_class_name( $element ) {
10211027
* @since 6.4.0 Added `background.backgroundImage`.
10221028
* @since 6.5.0 Added `background.backgroundSize` and `dimensions.aspectRatio`.
10231029
* @since 7.0.0 Added `dimensions.width` and `dimensions.height`.
1030+
* @since 7.1.0 Added `background.gradient`.
10241031
* @var array
10251032
*/
10261033
const APPEARANCE_TOOLS_OPT_INS = array(
10271034
array( 'background', 'backgroundImage' ),
10281035
array( 'background', 'backgroundSize' ),
1036+
array( 'background', 'gradient' ),
10291037
array( 'border', 'color' ),
10301038
array( 'border', 'radius' ),
10311039
array( 'border', 'style' ),
@@ -2945,11 +2953,21 @@ protected static function compute_style_properties( $styles, $settings = array()
29452953
* For uploaded image (images with a database ID), apply size and position defaults,
29462954
* equal to those applied in block supports in lib/background.php.
29472955
*/
2948-
if ( 'background-image' === $css_property && ! empty( $value ) ) {
2949-
$background_styles = wp_style_engine_get_styles(
2950-
array( 'background' => array( 'backgroundImage' => $value ) )
2951-
);
2952-
$value = $background_styles['declarations'][ $css_property ];
2956+
if ( 'background-image' === $css_property ) {
2957+
$background_image_input = array();
2958+
if ( ! empty( $value ) ) {
2959+
$background_image_input['backgroundImage'] = $value;
2960+
}
2961+
$gradient_value = $styles['background']['gradient'] ?? null;
2962+
if ( ! empty( $gradient_value ) ) {
2963+
$background_image_input['gradient'] = $gradient_value;
2964+
}
2965+
if ( ! empty( $background_image_input ) ) {
2966+
$background_styles = wp_style_engine_get_styles(
2967+
array( 'background' => $background_image_input )
2968+
);
2969+
$value = $background_styles['declarations'][ $css_property ] ?? null;
2970+
}
29532971
}
29542972
if ( empty( $value ) && static::ROOT_BLOCK_SELECTOR !== $selector && ! empty( $styles['background']['backgroundImage']['id'] ) ) {
29552973
if ( 'background-size' === $css_property ) {

src/wp-includes/kses.php

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2553,6 +2553,7 @@ function kses_init() {
25532553
* @since 6.5.0 Added support for `background-repeat`.
25542554
* @since 6.6.0 Added support for `grid-column`, `grid-row`, and `container-type`.
25552555
* @since 6.9.0 Added support for `white-space`.
2556+
* @since 7.1.0 Extended gradient support to allow any single-level nested function.
25562557
*
25572558
* @param string $css A string of CSS rules, decoded from an HTML `style` attribute.
25582559
* @param string $deprecated Not used.
@@ -2900,10 +2901,16 @@ function safecss_filter_attr( $css, $deprecated = '' ) {
29002901
}
29012902

29022903
if ( $found && $gradient_attr ) {
2903-
$css_value = trim( $parts[1] );
2904-
if ( preg_match( '/^(repeating-)?(linear|radial|conic)-gradient\(([^()]|rgb[a]?\([^()]*\))*\)$/', $css_value ) ) {
2905-
// Remove the whole `gradient` bit that was matched above from the CSS.
2906-
$css_test_string = str_replace( $css_value, '', $css_test_string );
2904+
/*
2905+
* Match every `*-gradient()` in the value, allowing one level of nested functions
2906+
* (e.g. rgb(), hsl(), var()). Matching each occurrence, rather than requiring the
2907+
* whole value to be a single gradient, lets a gradient combine with a url() image.
2908+
*/
2909+
preg_match_all( '/(?:repeating-)?(?:linear|radial|conic)-gradient\((?:[^()]|\([^()]*\))*\)/', $css_test_string, $gradient_matches );
2910+
2911+
foreach ( $gradient_matches[0] as $gradient_match ) {
2912+
// Remove each `gradient()` bit that was matched above from the CSS.
2913+
$css_test_string = str_replace( $gradient_match, '', $css_test_string );
29072914
}
29082915
}
29092916

src/wp-includes/style-engine/class-wp-style-engine.php

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ final class WP_Style_Engine {
4848
* - value_func => (string) the name of a function to generate a CSS definition array for a particular style object. The output of this function should be `array( "$property" => "$value", ... )`.
4949
*
5050
* @since 6.1.0
51+
* @since 7.1.0 Added `background.gradient` property.
5152
* @var array
5253
*/
5354
const BLOCK_STYLE_DEFINITIONS_METADATA = array(
@@ -83,6 +84,18 @@ final class WP_Style_Engine {
8384
),
8485
'path' => array( 'background', 'backgroundAttachment' ),
8586
),
87+
'gradient' => array(
88+
'property_keys' => array(
89+
'default' => 'background-image',
90+
),
91+
'css_vars' => array(
92+
'gradient' => '--wp--preset--gradient--$slug',
93+
),
94+
'path' => array( 'background', 'gradient' ),
95+
'classnames' => array(
96+
'has-background' => true,
97+
),
98+
),
8699
),
87100
'color' => array(
88101
'text' => array(
@@ -495,6 +508,13 @@ public static function parse_block_styles( $block_styles, $options ) {
495508

496509
$css_declarations = static::get_css_declarations( $style_value, $style_definition, $options );
497510
if ( ! empty( $css_declarations ) ) {
511+
/*
512+
* Combine background gradient and background image into a single
513+
* comma-separated background-image value, matching the JS style engine.
514+
*/
515+
if ( isset( $css_declarations['background-image'] ) && isset( $parsed_styles['declarations']['background-image'] ) ) {
516+
$css_declarations['background-image'] = $css_declarations['background-image'] . ', ' . $parsed_styles['declarations']['background-image'];
517+
}
498518
$parsed_styles['declarations'] = array_merge( $parsed_styles['declarations'], $css_declarations );
499519
}
500520
}

0 commit comments

Comments
 (0)