Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ Settings related to background.
| backgroundImage | Allow users to set a background image. | `boolean` | `false` |
| backgroundSize | Allow users to set values related to the size of a background image, including size, position, and repeat controls. | `boolean` | `false` |
| gradient | Allow users to set a gradient background. | `boolean` | `false` |
| backgroundClip | Allow users to set background clip. Pass true for all methods, or an array of CSS values: ["text", "padding-box", "border-box", "content-box"]. | `boolean`, `[ string ]` | |

---

Expand Down
18 changes: 15 additions & 3 deletions lib/block-supports/background.php
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,10 @@ function gutenberg_render_background_support( $block_content, $block ) {
$block_attributes = ( isset( $block['attrs'] ) && is_array( $block['attrs'] ) ) ? $block['attrs'] : array();
$has_background_image_support = block_has_support( $block_type, array( 'background', 'backgroundImage' ), false );
$has_background_gradient_support = block_has_support( $block_type, array( 'background', 'gradient' ), false );
$has_background_clip_support = block_has_support( $block_type, array( 'background', 'backgroundClip' ), false );

if (
( ! $has_background_image_support && ! $has_background_gradient_support ) ||
( ! $has_background_image_support && ! $has_background_gradient_support && ! $has_background_clip_support ) ||
! isset( $block_attributes['style']['background'] )
) {
return $block_content;
Expand All @@ -55,8 +56,9 @@ function gutenberg_render_background_support( $block_content, $block ) {
// Check serialization skip for each feature individually.
$skip_background_image = ! $has_background_image_support || wp_should_skip_block_supports_serialization( $block_type, 'background', 'backgroundImage' );
$skip_background_gradient = ! $has_background_gradient_support || wp_should_skip_block_supports_serialization( $block_type, 'background', 'gradient' );
$skip_background_clip = ! $has_background_clip_support || wp_should_skip_block_supports_serialization( $block_type, 'background', 'backgroundClip' );

if ( $skip_background_image && $skip_background_gradient ) {
if ( $skip_background_image && $skip_background_gradient && $skip_background_clip ) {
return $block_content;
}

Expand All @@ -81,6 +83,10 @@ function gutenberg_render_background_support( $block_content, $block ) {
$background_styles['gradient'] = $block_attributes['style']['background']['gradient'] ?? null;
}

if ( ! $skip_background_clip ) {
$background_styles['backgroundClip'] = $block_attributes['style']['background']['backgroundClip'] ?? null;
}

$styles = gutenberg_style_engine_get_styles( array( 'background' => $background_styles ) );

if ( ! empty( $styles['css'] ) ) {
Expand All @@ -97,7 +103,13 @@ function gutenberg_render_background_support( $block_content, $block ) {
}

$tags->set_attribute( 'style', $updated_style );
$tags->add_class( 'has-background' );
// Skip has-background when the gradient is used as a text fill via
// background-clip: text, as the visual effect is on the text, not the background.
$is_text_gradient = isset( $block_attributes['style']['background']['backgroundClip'] )
&& 'text' === $block_attributes['style']['background']['backgroundClip'];
if ( ! $is_text_gradient ) {
$tags->add_class( 'has-background' );
}
}

return $tags->get_updated_html();
Expand Down
7 changes: 6 additions & 1 deletion lib/block-supports/colors.php
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,12 @@ function gutenberg_apply_colors_support( $block_type, $block_attributes ) {
}

$attributes = array();
$styles = gutenberg_style_engine_get_styles( array( 'color' => $color_block_styles ), array( 'convert_vars_to_classnames' => true ) );
$styles = gutenberg_style_engine_get_styles(
array( 'color' => $color_block_styles ),
array(
'convert_vars_to_classnames' => true,
)
);

if ( ! empty( $styles['classnames'] ) ) {
$attributes['class'] = $styles['classnames'];
Expand Down
30 changes: 30 additions & 0 deletions lib/class-wp-theme-json-gutenberg.php
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,7 @@ class WP_Theme_JSON_Gutenberg {
'background-repeat' => array( 'background', 'backgroundRepeat' ),
'background-size' => array( 'background', 'backgroundSize' ),
'background-attachment' => array( 'background', 'backgroundAttachment' ),
'background-clip' => array( 'background', 'backgroundClip' ),
'border-radius' => array( 'border', 'radius' ),
'border-top-left-radius' => array( 'border', 'radius', 'topLeft' ),
'border-top-right-radius' => array( 'border', 'radius', 'topRight' ),
Expand Down Expand Up @@ -396,6 +397,7 @@ class WP_Theme_JSON_Gutenberg {
'appearanceTools' => null,
'useRootPaddingAwareAlignments' => null,
'background' => array(
'backgroundClip' => null,
'backgroundImage' => null,
'backgroundSize' => null,
'gradient' => null,
Expand Down Expand Up @@ -526,6 +528,7 @@ class WP_Theme_JSON_Gutenberg {
*/
const VALID_STYLES = array(
'background' => array(
'backgroundClip' => null,
'backgroundImage' => null,
'backgroundAttachment' => null,
'backgroundPosition' => null,
Expand Down Expand Up @@ -783,6 +786,7 @@ public static function get_element_class_name( $element ) {
* @var array
*/
const APPEARANCE_TOOLS_OPT_INS = array(
array( 'background', 'backgroundClip' ),
array( 'background', 'backgroundImage' ),
array( 'background', 'backgroundSize' ),
array( 'background', 'gradient' ),
Expand Down Expand Up @@ -2619,6 +2623,32 @@ protected static function compute_style_properties( $styles, $settings = array()
'name' => $css_property,
'value' => $value,
);

// When background-clip is set, add vendor-prefixed properties for
// cross-browser support. For 'text', this clips the background to
// the text and makes it visible via transparent fill. For box-model
// values, unset the fill color to cancel any inherited text gradient.
if ( 'background-clip' === $css_property ) {
if ( 'text' === $value ) {
$declarations[] = array(
'name' => '-webkit-background-clip',
'value' => 'text',
);
$declarations[] = array(
'name' => '-webkit-text-fill-color',
'value' => 'transparent',
);
} else {
$declarations[] = array(
'name' => '-webkit-background-clip',
'value' => 'unset',
);
$declarations[] = array(
'name' => '-webkit-text-fill-color',
'value' => 'unset',
);
}
}
}

// If a variable value is added to the root, the corresponding property should be removed.
Expand Down
26 changes: 26 additions & 0 deletions lib/compat/wordpress-7.0/kses.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,29 @@ function gutenberg_add_display_to_safe_style_css( $attr ) {
return $attr;
}
add_filter( 'safe_style_css', 'gutenberg_add_display_to_safe_style_css' );

/**
* Add background-clip and related vendor-prefixed properties to the list of
* safe CSS properties. Without these, `safecss_filter_attr()` strips the
* declarations generated by the background-clip block support, which causes
* the style engine to return an empty `css` string.
*
* @param string[] $attr List of allowed CSS attributes.
* @return string[] Modified list of allowed CSS attributes.
*/
function gutenberg_add_background_clip_to_safe_style_css( $attr ) {
$background_clip_attrs = array(
'background-clip',
'-webkit-background-clip',
'-webkit-text-fill-color',
);

foreach ( $background_clip_attrs as $background_clip_attr ) {
if ( ! in_array( $background_clip_attr, $attr, true ) ) {
$attr[] = $background_clip_attr;
}
}

return $attr;
}
add_filter( 'safe_style_css', 'gutenberg_add_background_clip_to_safe_style_css' );
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,7 @@ export function useSettingsForBlockElement(
[ 'backgroundImage', 'backgroundImage' ],
[ 'backgroundSize', 'backgroundSize' ],
[ 'backgroundGradient', 'gradient' ],
[ 'backgroundClip', 'backgroundClip' ],
].forEach( ( [ styleKey, settingKey ] ) => {
if ( ! supportedStyles.includes( styleKey ) ) {
updatedSettings.background = {
Expand Down
3 changes: 2 additions & 1 deletion packages/block-editor/src/hooks/background.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,8 @@ export function hasBackgroundSupport( blockName, feature = 'any' ) {
!! support?.backgroundImage ||
!! support?.backgroundSize ||
!! support?.backgroundRepeat ||
!! support?.gradient
!! support?.gradient ||
!! support?.backgroundClip
);
}

Expand Down
11 changes: 10 additions & 1 deletion packages/block-editor/src/hooks/style.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,16 @@ export function getInlineStyles( styles = {} ) {
// The goal is to move everything to server side generated engine styles
// This is temporary as we absorb more and more styles into the engine.
getCSSRules( styles ).forEach( ( rule ) => {
output[ rule.key ] = rule.value;
// Vendor-prefixed CSS properties start with a dash (e.g. `-webkit-background-clip`).
// React style objects require camelCase keys without the leading dash
// (e.g. `WebkitBackgroundClip`), so convert them here.
const key = rule.key.startsWith( '-' )
? rule.key
.slice( 1 )
.replace( /-([a-z])/g, ( _, c ) => c.toUpperCase() )
.replace( /^[a-z]/, ( c ) => c.toUpperCase() )
: rule.key;
output[ key ] = rule.value;
} );

return output;
Expand Down
4 changes: 4 additions & 0 deletions packages/block-editor/src/hooks/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,7 @@ export function useBlockSettings( name, parentLayout ) {
backgroundImage,
backgroundSize,
gradient,
backgroundClip,
customFontFamilies,
defaultFontFamilies,
themeFontFamilies,
Expand Down Expand Up @@ -302,6 +303,7 @@ export function useBlockSettings( name, parentLayout ) {
'background.backgroundImage',
'background.backgroundSize',
'background.gradient',
'background.backgroundClip',
'typography.fontFamilies.custom',
'typography.fontFamilies.default',
'typography.fontFamilies.theme',
Expand Down Expand Up @@ -369,6 +371,7 @@ export function useBlockSettings( name, parentLayout ) {
backgroundImage,
backgroundSize,
gradient,
backgroundClip,
},
color: {
palette: {
Expand Down Expand Up @@ -457,6 +460,7 @@ export function useBlockSettings( name, parentLayout ) {
backgroundImage,
backgroundSize,
gradient,
backgroundClip,
customFontFamilies,
defaultFontFamilies,
themeFontFamilies,
Expand Down
5 changes: 5 additions & 0 deletions packages/blocks/src/api/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,11 @@ export const __EXPERIMENTAL_STYLE_PROPERTY = {
support: [ 'background', 'gradient' ],
useEngine: true,
},
backgroundClip: {
value: [ 'background', 'backgroundClip' ],
support: [ 'background', 'backgroundClip' ],
useEngine: true,
},
borderColor: {
value: [ 'border', 'color' ],
support: [ '__experimentalBorder', 'color' ],
Expand Down
2 changes: 1 addition & 1 deletion packages/global-styles-engine/src/core/render.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -659,7 +659,7 @@ export function getStylesDeclarations(
) {
return;
}
const cssProperty = rule.key.startsWith( '--' )
const cssProperty = rule.key.startsWith( '-' )
? rule.key
: kebabCase( rule.key );

Expand Down
1 change: 1 addition & 0 deletions packages/global-styles-engine/src/settings/get-setting.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import type { GlobalStylesConfig } from '../types';
const VALID_SETTINGS = [
'appearanceTools',
'useRootPaddingAwareAlignments',
'background.backgroundClip',
'background.backgroundImage',
'background.backgroundRepeat',
'background.backgroundSize',
Expand Down
87 changes: 78 additions & 9 deletions packages/style-engine/src/class-wp-style-engine.php
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,10 @@ final class WP_Style_Engine {
'has-background' => true,
),
),
'backgroundClip' => array(
'value_func' => array( self::class, 'get_background_clip_css_declarations' ),
'path' => array( 'background', 'backgroundClip' ),
),
),
'color' => array(
'text' => array(
Expand Down Expand Up @@ -114,17 +118,14 @@ final class WP_Style_Engine {
),
),
'gradient' => array(
'property_keys' => array(
'property_keys' => array(
'default' => 'background',
),
'css_vars' => array(
'css_vars' => array(
'gradient' => '--wp--preset--gradient--$slug',
),
'path' => array( 'color', 'gradient' ),
'classnames' => array(
'has-background' => true,
'has-$slug-gradient-background' => 'gradient',
),
'path' => array( 'color', 'gradient' ),
'classnames_func' => array( self::class, 'get_gradient_classnames' ),
),
),
'border' => array(
Expand Down Expand Up @@ -460,7 +461,7 @@ public static function parse_block_styles( $block_styles, $options ) {
continue;
}

$classnames = static::get_classnames( $style_value, $style_definition );
$classnames = static::get_classnames( $style_value, $style_definition, $options );
if ( ! empty( $classnames ) ) {
$parsed_styles['classnames'] = array_merge( $parsed_styles['classnames'], $classnames );
}
Expand Down Expand Up @@ -490,11 +491,15 @@ public static function parse_block_styles( $block_styles, $options ) {
*
* @return array|string[] An array of CSS classnames, or empty array.
*/
protected static function get_classnames( $style_value, $style_definition ) {
protected static function get_classnames( $style_value, $style_definition, $options = array() ) {
if ( empty( $style_value ) ) {
return array();
}

if ( isset( $style_definition['classnames_func'] ) && is_callable( $style_definition['classnames_func'] ) ) {
return call_user_func( $style_definition['classnames_func'], $style_value, $style_definition, $options );
}

$classnames = array();
if ( ! empty( $style_definition['classnames'] ) ) {
foreach ( $style_definition['classnames'] as $classname => $property_key ) {
Expand Down Expand Up @@ -676,6 +681,70 @@ protected static function get_url_or_value_css_declaration( $style_value, $style
return $css_declarations;
}

/**
* Style value parser that returns CSS declarations for background-clip.
*
* When the value is 'text', this also outputs the necessary vendor-prefixed
* properties to clip the background to the text.
*
* @param string $style_value A single raw style value from $block_styles array.
* @param array $style_definition A single style definition from BLOCK_STYLE_DEFINITIONS_METADATA.
*
* @return string[] An associative array of CSS definitions, e.g., array( "$property" => "$value", "$property" => "$value" ).
*/
// phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable -- Required by value_func callback signature.
protected static function get_background_clip_css_declarations( $style_value, $style_definition ) {
if ( empty( $style_value ) || ! is_string( $style_value ) ) {
return array();
}

$valid_values = array( 'border-box', 'padding-box', 'content-box', 'text' );
if ( ! in_array( $style_value, $valid_values, true ) ) {
return array();
}

$css_declarations = array(
'background-clip' => $style_value,
);

if ( 'text' === $style_value ) {
$css_declarations['-webkit-background-clip'] = 'text';
$css_declarations['-webkit-text-fill-color'] = 'transparent';
} else {
$css_declarations['-webkit-background-clip'] = 'unset';
$css_declarations['-webkit-text-fill-color'] = 'unset';
}

return $css_declarations;
}

/**
* Returns classnames for a gradient color value.
*
* @since 6.8.0
*
* @param string $style_value The gradient style value.
* @param array $style_definition The style definition from BLOCK_STYLE_DEFINITIONS_METADATA.
* @param array $options Optional. An array of options.
*
* @return string[] An array of CSS classnames.
*/
// phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable -- Required by classnames_func callback signature.
protected static function get_gradient_classnames( $style_value, $style_definition, $options = array() ) {
if ( empty( $style_value ) ) {
return array();
}

$classnames = array( 'has-background' );

$slug = static::get_slug_from_preset_value( $style_value, 'gradient' );
if ( $slug ) {
$classnames[] = "has-{$slug}-gradient-background";
}

return $classnames;
}

/**
* Returns compiled CSS from css_declarations.
*
Expand Down
Loading
Loading