块编辑器开发文档

使用样式引擎生成块支持样式

💡 云策文档标注

概述

本文档介绍了如何使用 WordPress 样式引擎(Style Engine)来处理块支持(block supports)样式,包括生成 CSS 和类名。核心是通过 wp_style_engine_get_styles 函数将样式对象转换为前端可用的样式属性,并支持预设值和序列化控制。

关键要点

  • 块支持 API 允许块声明对特定样式特性的支持,扩展属性中的 style 对象。
  • 使用 wp_style_engine_get_styles 函数将样式对象编译为 CSS 字符串和声明数组,适用于服务器端渲染块。
  • 在注册块支持时,通过 apply 回调应用样式,需检查块是否支持样式或跳过序列化,使用 wp_should_skip_block_supports_serialization 和 block_has_support 函数。
  • 样式引擎支持从预设值生成类名和 CSS 自定义属性,预设值格式为 var:preset|<PRESET_TYPE>|<PRESET_SLUG>。
  • 可通过选项数组中的 convert_vars_to_classnames 标志控制是否将 CSS 自定义变量转换为类名。

代码示例

$block_styles =  array(
    'spacing' => array( 'padding' => '10px', 'margin' => array( 'top' => '1em') ),
    'typography' => array( 'fontSize' => '2.2rem' ),
);
$styles = wp_style_engine_get_styles(
    $block_styles
);
print_r( $styles );

注意事项

  • 样式引擎目前仅为核心块支持(border、color、spacing、typography)生成样式,未来版本可能扩展。
  • 在应用样式前,需验证主题支持和块序列化设置,避免无效样式输出。
  • 预设值处理需遵循特定格式,以确保正确生成 CSS 和类名。

📄 原文内容

Block supports is the API that allows a block to declare support for certain features.

Where a block declares support for a specific style group or property, e.g., “spacing” or “spacing.padding”, the block’s attributes are extended to include a style object.

For example:

{
    "attributes": {
        "style": {
            "spacing": {
                "margin": {
                    "top": "10px"
                },
                "padding": "1em"
            },
            "typography": {
                "fontSize": "2.2rem"
            }
        }
    }
}

Using this object, the Style Engine can generate the classes and CSS required to style the block element.

The global function wp_style_engine_get_styles accepts a style object as its first argument, and will output compiled CSS and an array of CSS declaration property/value pairs.

$block_styles =  array(
    'spacing' => array( 'padding' => '10px', 'margin' => array( 'top' => '1em') ),
    'typography' => array( 'fontSize' => '2.2rem' ),
);
$styles = wp_style_engine_get_styles(
    $block_styles
);
print_r( $styles );

/*
array(
    'css'          => 'padding:10px;margin-top:1em;font-size:2.2rem',
    'declarations' => array( 'padding' => '10px', 'margin-top' => '1em', 'font-size' => '2.2rem' )
)
*/

Use case

When registering a block support, it is possible to pass an ‘apply’ callback in the block support config array to add or extend block support attributes with “class” or “style” properties.

If a block has opted into the block support, the values of “class” and “style” will be applied to the block element’s “class” and “style” attributes accordingly when rendered in the frontend HTML. Note, this applies only to server-side rendered blocks, for example, the Site Title block.

The callback receives $block_type and $block_attributes as arguments. The style attribute within $block_attributes only contains the raw style object, if any styles have been set for the block, and not any CSS or classnames to be applied to the block’s HTML elements.

Here is where wp_style_engine_get_styles comes in handy: it will generate CSS and, if appropriate, classnames to be added to the “style” and “class” HTML attributes in the final rendered block markup.

Here is a very simplified version of how the color block support works:

function gutenberg_apply_colors_support( $block_type, $block_attributes ) {
    // Get the color styles from the style object.
    $block_color_styles = isset( $block_attributes['style']['color'] ) ? $block_attributes['style']['color'] : null;

    // Since we only want the color styles, pass the color styles only to the Style Engine.
    $styles = wp_style_engine_get_styles( array( 'color' => $block_color_styles ) );

    // Return the generated styles to be applied to the block's HTML element.
    return array(
        'style' => $styles['css'],
        'class' => $styles['classnames']
    );
}

// Register the block support.
WP_Block_Supports::get_instance()->register(
    'colors',
    array(
        'register_attribute' => 'gutenberg_register_colors_support',
        'apply'              => 'gutenberg_apply_colors_support',
    )
);

It’s important to note that, for now, the Style Engine will only generate styles for the following, core block supports:

  • border
  • color
  • spacing
  • typography

In future releases, it will be possible to extend this list.

Checking for block support and skip serialization

Before passing the block style object to the Style Engine, you’ll need to take into account:

  1. whether the theme has elected to support a particular block style, and
  2. whether a block has elected to “skip serialization” of that particular block style, that is, opt-out of automatic application of styles to the block’s element (usually in order to do it via the block’s internals). See the block API documentation for further information.

If a block either:

  • has no support for a style, or
  • skips serialization of that style

it’s likely that you’ll want to remove those style values from the style object before passing it to the Style Engine with help of two functions:

We can now update the “apply” callback code above so that we’ll only return “style” and “class”, where a block has support, and it doesn’t skip serialization:

function gutenberg_apply_colors_support( $block_type, $block_attributes ) {
    // The return value.
    $attributes = array();

    // Return early if the block skips all serialization for block supports.
    if ( gutenberg_should_skip_block_supports_serialization( $block_type, 'color' ) ) {
        return $attributes;
    }

    // Checks for support and skip serialization.
    $has_text_support                        = block_has_support( $block_type, array( 'color', 'text' ), false );
    $has_background_support                  = block_has_support( $block_type, array( 'color', 'background' ), false );
    $skips_serialization_of_color_text       = wp_should_skip_block_supports_serialization( $block_type, 'color', 'text' );
    $skips_serialization_of_color_background = wp_should_skip_block_supports_serialization( $block_type, 'color', 'background' );

    // Get the color styles from the style object.
    $block_color_styles = isset( $block_attributes['style']['color'] ) ? $block_attributes['style']['color'] : null;

    // The mutated styles object we're going to pass to wp_style_engine_get_styles().
    $color_block_styles = array();

    // Set the color style values according to whether the block has support and does not skip serialization.
    $spacing_block_styles['text']       = null;
    $spacing_block_styles['background'] = null;
    if ( $has_text_support && ! $skips_serialization_of_color_text ) {
        $spacing_block_styles['text'] = $block_color_styles['text'] ?? null;
    }
    if $has_background_support && ! $skips_serialization_of_color_background ) {
        $spacing_block_styles['background'] = $block_color_styles['background'] ?? null;
    }

    // Pass the color styles, excluding those that have no support or skip serialization, to the Style Engine.
    $styles = wp_style_engine_get_styles( array( 'color' => $block_color_styles ) );

    // Return the generated styles to be applied to the block's HTML element.
    return array(
        'style' => $styles['css'],
        'class' => $styles['classnames']
    );
}

Generating classnames and CSS custom selectors from presets

Many of theme.json’s presets will generate both CSS custom properties and CSS rules (consisting of a selector and the CSS declarations) on the frontend.

Styling a block using these presets normally involves adding the selector to the “className” attribute of the block.

For styles that can have preset values, such as text color and font family, the Style Engine knows how to construct the classnames using the preset slug.

To discern CSS values from preset values, the Style Engine expects a special format.

Preset values must follow the pattern var:preset|<PRESET_TYPE>|<PRESET_SLUG>.

When the Style Engine encounters these values, it will parse them and create a CSS value of var(--wp--preset--font-size--small) and/or generate a classname if required.

Example:

// Let's say the block attributes styles contain a fontSize preset slug of "small".
// $block_attributes['fontSize'] = 'var:preset|font-size|small';
$preset_font_size        = "var:preset|font-size|{$block_attributes['fontSize']}";
// Now let's say the block attributes styles contain a backgroundColor preset slug of "blue".
// $block_attributes['backgroundColor'] = 'var:preset|color|blue';
$preset_background_color = "var:preset|color|{$block_attributes['backgroundColor']}";

$block_styles =  array(
    'typography' => array( 'fontSize' => $preset_font_size ),
    'color'      => array( 'background' => $preset_background_color ),
    'spacing'    => array( 'padding' => '10px', 'margin' => array( 'top' => '1em') ),
);

$styles = wp_style_engine_get_styles(
    $block_styles
);
print_r( $styles );

/*
array(
    'css'          => 'background-color:var(--wp--preset--color--blue);padding:10px;margin-top:1em;font-size:var(--wp--preset--font-size--small);',
    'declarations' => array(
        'background-color' => 'var(--wp--preset--color--blue)',
        'padding' => '10px',
        'margin-top' => '1em',
        'font-size' => 'var(--wp--preset--font-size--small)',
    ),
    'classnames'   => 'has-background has-blue-background-color has-small-font-size',
)
*/

If you don’t want the Style Engine to output the CSS custom vars in the generated CSS string as well, which you might not if you’re applying both the CSS rules and classnames to the block element, you can pass 'convert_vars_to_classnames' => true in the options array.

This flag means “convert the vars to classnames and don’t output the vars to the CSS”. The Style Engine will therefore only generate the required classnames and omit the CSS custom vars in the CSS.

Using the above example code, observe the different output when we pass the option:

$options = array(
    'convert_vars_to_classnames' => true,
);

$styles = wp_style_engine_get_styles(
    $block_styles,
    $options
);
print_r( $styles );

/*
array(
    'css'          => 'padding:10px;margin-top:1em;',
    'declarations' => array(
        'padding' => '10px',
        'margin-top' => '1em',
    ),
    'classnames'   => 'has-background has-blue-background-color has-small-font-size',
)
*/

Read more about global styles and preset CSS custom properties and theme supports.