区块变体 API 允许您定义区块的多个版本(变体)。区块变体与原始区块的区别在于一组初始属性或内部区块。当您将区块变体插入编辑器时,这些属性和/或内部区块会被应用。

变体是创建现有区块迭代版本的绝佳方式,而无需从头构建全新的区块。

为了更好地理解此 API,请考虑嵌入(Embed)区块。该区块包含每种可嵌入内容类型(WordPress、YouTube 等)的众多变体。每个嵌入区块变体共享相同的底层功能,用于编辑、保存等。除了名称和描述信息外,主要区别是 providerNameSlug 属性。下面是嵌入区块变体的简化示例。查看 源代码 以获取完整规范。

variations: [
    {
        name: 'wordpress',
        title: 'WordPress',
        description: __( 'Embed a WordPress post.' ),
        attributes: { providerNameSlug: 'wordpress' },
    },
    {
        name: 'youtube',
        title: 'YouTube',
        description: __( 'Embed a YouTube video.' ),
        attributes: { providerNameSlug: 'youtube' },
    },
],

定义区块变体

区块变体由一个对象定义,该对象可以包含以下字段:

  • name(类型 string)– 唯一且机器可读的名称。
  • title(可选,类型 string)– 人类可读的变体标题。
  • description(可选,类型 string)– 人类可读的变体描述。
  • category(可选,类型 string)– 在搜索界面中用于按类别排列区块类型的分类。
  • keywords(可选,类型 string[])– 帮助用户在搜索时发现变体的术语数组(这些术语可以翻译)。
  • icon(可选,类型 string | Object)– 帮助可视化变体的图标。它可以具有与区块类型相同的形状。
  • attributes(可选,类型 Object)– 覆盖区块属性的值。
  • innerBlocks(可选,类型 Array[])– 嵌套区块的初始配置。
  • innerContent(可选,类型 Array)– 与内部区块交错在一起的静态 HTML 片段,其中 null 条目标记静态标记中内部区块的位置。仅适用于自定义 HTML 区块。
  • example(可选,类型 Object)– 为区块预览提供结构化数据。设置为 undefined 以禁用预览。有关更多详细信息,请参阅 区块注册 API。
  • scope(可选,类型 WPBlockVariationScope[])– 默认为 block 和 inserter。变体适用的作用域列表。可用选项包括:
    • block – 用于区块过滤特定区块变体。Columns 和 Query 区块具有此类变体,这些变体会传递给 实验性 BlockVariationPicker 组件。该组件负责显示变体并允许用户选择其中一个。
    • inserter – 区块变体在插入器上显示。
    • transform – 区块变体在用于变体转换的组件中显示。
  • isDefault(可选,类型 boolean)– 默认为 false。指示当前变体是否为默认变体(详见下文)。
  • isActive(可选,类型 Function|string[])– 用于确定在选中区块时变体是否激活的函数或区块属性数组。该函数接受 blockAttributes 和 variationAttributes(详见下文)。
  • shortcut(可选,类型 Object)– 将变体应用于所选区块的键盘快捷键(详见下文)。
从技术上讲,您可以创建一个没有唯一 name 的区块变体,但这不推荐。唯一的 name 允许编辑器区分您的变体和其他可能存在的变体。它还允许根据需要取消注册您的变体,并对 isDefault 设置产生影响(详见下文)。

创建区块变体

可以通过在区块注册期间提供带有适当变体对象数组的 variations 键来声明区块变体,如上例所示。有关更多详细信息,请参阅 区块注册 API。

要为现有区块(如核心区块)创建变体,请使用 wp.blocks.registerBlockVariation()。该函数接受区块名称和定义变体的对象。

wp.blocks.registerBlockVariation( 'core/embed', {
    name: 'custom-embed',
    attributes: { providerNameSlug: 'custom' },
} );

在 PHP 中注册区块变体

也可以使用 get_block_type_variations 过滤器钩子从 PHP 注册区块变体。这种方法在您需要根据注册的帖子类型、分类或其他 WordPress 数据动态生成变体时特别有用。

以下是为 core/image 区块注册自定义变体的示例:

function my_custom_image_variation( $variations, $block_type ) {
    // Only modify variations for the image block
    if ( 'core/image' !== $block_type->name ) {
        return $variations;
    }

    // Add a custom variation
    $variations[] = array(
        'name'        => 'wide-image',
        'title'       => __( 'Wide image', 'textdomain' ),
        'description' => __( 'A wide image', 'textdomain' ),
        'scope'       => array( 'inserter' ),
        'isDefault'   => false,
        'attributes'  => array(
            'align' => 'wide', // Identifies the link type as custom
        ),
    );

    return $variations;
}
add_filter( 'get_block_type_variations', 'my_custom_image_variation', 10, 2 );

当请求区块类型的变体时,会调用 get_block_type_variations 过滤器。它接收两个参数:
– $variations:当前注册的区块类型变体数组
– $block_type:完整的区块类型对象

请注意,通过 PHP 注册的变体会与使用 registerBlockVariation() 通过 JavaScript 注册的任何变体合并。

查看 如何使用 PHP 注册区块变体 博客文章以获取有关此主题的更多信息

移除区块变体

区块变体也可以轻松移除。为此,请使用 wp.blocks.unregisterBlockVariation()。该函数接受区块名称和应取消注册的变体的 name。

wp.blocks.unregisterBlockVariation( 'core/embed', 'youtube' );

区块变体与区块样式

区块样式和区块变体的主要区别在于,区块样式只是将 CSS 类应用于区块,因此可以以替代方式对其进行样式设置。有关更多详细信息,请参阅 区块样式 API。

如果您想应用初始属性或内部区块,这属于区块变体范畴。在定义区块变体时,也可以使用 className 属性覆盖默认区块样式。

variations: [
    {
        name: 'blue',
        title: __( 'Blue Quote' ),
        isDefault: true,
        attributes: {
            color: 'blue',
            className: 'is-style-blue-quote'
        },
        icon: 'format-quote',
        isActive: ( blockAttributes, variationAttributes ) =>
            blockAttributes.color === variationAttributes.color
    },
],

使用 isDefault

默认情况下,所有变体都会与原始区块类型项目一起显示在插入器中。但是,为列出的任何变体设置 isDefault 标志将覆盖插入器中的常规区块类型。这是一个很好的工具,可用于根据特定需求定制编辑器体验。

例如,如果您希望媒体和文本区块默认在右侧显示图像,您可以创建如下所示的变体:

wp.blocks.registerBlockVariation( 'core/media-text', {
    name: 'media-text-media-right',
    title: __( 'Media & Text' ),
    isDefault: true,
    attributes: {
        mediaPosition: 'right',
    },
} );

使用 isDefault 的注意事项

虽然在使用没有现有变体的块时,isDefault 效果很好,但在存在其他变体时可能会遇到问题。

如果同一块的另一个变体使用了 isDefault,您的变体不一定能成为默认值。编辑器会尊重第一个注册的带有 isDefault 的变体,这可能不是您的变体。

解决方案是在注册带有 isDefault 的变体之前取消注册其他变体。这个注意事项加强了始终为变体提供唯一 name 的建议。否则,无法取消注册该变体。

使用 isActive

虽然 isActive 属性是可选的,但建议使用它。块编辑器使用该 API 来检查哪个变体处于活动状态,并在编辑器的实例中选择某个变体时显示该变体的正确标题、图标和描述。

如果未设置 isActive,编辑器无法区分原始块的实例和您的变体,因此将显示原始块的信息。

该属性可以设置为字符串数组 (string[]) 或函数。建议尽可能使用字符串数组版本。

string[] 版本用于声明应将其与给定变体的哪些块实例属性进行比较。每个属性都将进行检查,如果所有属性都匹配,则该变体将处于活动状态。

例如,在核心 Embed 块中,providerNameSlug 属性用于确定嵌入提供商(例如 'youtube' 或 'twitter')。变体可以这样声明:

const variations = [
    {
        name: 'twitter',
        title: 'Twitter',
        icon: embedTwitterIcon,
        keywords: [ 'tweet', __( 'social' ) ],
        description: __( 'Embed a tweet.' ),
        patterns: [ /^https?:\/\/(www\.)?twitter\.com\/.+/i ],
        attributes: { providerNameSlug: 'twitter', responsive: true },
    },
    {
        name: 'youtube',
        title: 'YouTube',
        icon: embedYouTubeIcon,
        keywords: [ __( 'music' ), __( 'video' ) ],
        description: __( 'Embed a YouTube video.' ),
        patterns: [
            /^https?:\/\/((m|www)\.)?youtube\.com\/.+/i,
            /^https?:\/\/youtu\.be\/.+/i,
        ],
        attributes: { providerNameSlug: 'youtube', responsive: true },
    },
    // ...
];

isActive 属性将如下所示:

isActive: [ 'providerNameSlug' ];

这将导致将块实例的 providerNameSlug 值与变体声明中声明的值(上面代码片段中的值)进行比较,以确定哪个嵌入变体处于活动状态。

嵌套对象路径也得到支持,自 WordPress 6.6.0 起。例如,考虑一个具有 query 对象的块变体作为属性。仅根据该对象的 postType 属性即可确定变体是否处于活动状态(同时忽略其所有其他属性):

isActive: [ 'query.postType' ];

此属性的函数版本接受块实例的 blockAttributes 作为第一个参数,以及为变体声明的 variationAttributes 作为第二个参数。可以使用这些参数通过比较它们并返回 true 或 false(指示该变体是否对此块实例不活动)来确定变体是否处于活动状态。

使用嵌入块的相同示例,函数版本将如下所示:

isActive: ( blockAttributes, variationAttributes ) =>
    blockAttributes.providerNameSlug === variationAttributes.providerNameSlug,

isActive 匹配的特定性

注意:自 WordPress 6.6.0 起改进处理。

如果有多个变体的 isActive 检查匹配给定的块实例,并且它们都是字符串数组,则选择具有最高 特定性 的变体。考虑以下示例:

wp.blocks.registerBlockVariation( 'core/paragraph', {
    name: 'paragraph-red',
    title: 'Red Paragraph',
    attributes: {
        textColor: 'vivid-red',
    },
    isActive: [ 'textColor' ],
} );

wp.blocks.registerBlockVariation( 'core/paragraph', {
    name: 'paragraph-red-grey',
    title: 'Red/Grey Paragraph',
    attributes: {
        textColor: 'vivid-red',
        backgroundColor: 'cyan-bluish-gray',
    },
    isActive: [ 'textColor', 'backgroundColor' ],
} );

如果块实例具有属性 textColor: vivid-red 和 backgroundColor: cyan-bluish-gray,则两个变体的 isActive 标准都将匹配该块实例。在这种情况下,将确定更 具体 的匹配为活动变体,其中特定性计算为每个 isActive 数组的长度。这意味着 Red/Grey Paragraph 将显示为活动变体。

请注意,如果匹配的变体的 isActive 属性是函数而不是 string[],则无法确定其特定性。在这种情况下,第一个匹配的变体将被确定为活动变体。出于这个原因,通常建议使用 string[] 而不是 function 作为 isActive 属性。

使用 shortcut

变体可以声明适用于所选块的键盘快捷方式。该快捷方式与编辑器的键盘快捷方式存储注册,并列出在键盘快捷方式帮助模态框中。

shortcut 对象采用以下参数:

  • name(类型 string)——唯一且机器可读的快捷方式名称,例如 core/block-editor/transform-to-heading-2。
  • description(类型 string)——翻译后的描述,显示在键盘快捷方式帮助模态框中。
  • keyCombination(类型 Object)——触发快捷方式的键组合,作为 character 和可选的 modifier(wp-keycodes 包支持的修饰符之一,例如 access 或 primary)。
  • aliases(可选,类型 Object[])——触发相同快捷方式的替代键组合。

例如,核心 Heading 块为其每个级别变体提供快捷方式:

wp.blocks.registerBlockVariation( 'core/heading', {
    name: 'h2',
    title: 'Heading 2',
    attributes: { level: 2 },
    isActive: ( blockAttributes ) => blockAttributes.level === 2,
    shortcut: {
        name: 'core/block-editor/transform-to-heading-2',
        description: __( 'Transform the selected block into a heading 2.' ),
        keyCombination: { modifier: 'access', character: '2' },
    },
} );

快捷方式仅适用于已经是变体自己的块类型的块:它将变体的 attributes 设置在所选块上,并且当 isActive 报告该变体已经处于活动状态时不执行任何操作。在上面的示例中,这就是让快捷方式更改现有 Heading 块的级别的原因。

要从 不同 的块类型访问变体,请在产生此块的块转换上声明相同的快捷方式,给它相同的 name 和一个指向该变体的 variationName。Heading 块同时执行这两项操作,这就是为什么 Alt+Shift+2 将段落转换为 H2 以及更改现有标题的级别的原因。在几个地方声明一个快捷方式是预期的,只要每个声明都同意键组合和描述;这两个永远不会同时适用于同一选择。

快捷方式仅适用于完全可编辑的块,并且对于受限编辑模式(如仅内容编辑)中的块会被忽略。

键组合是全局匹配的,因此已被另一个块或编辑器本身占用的组合将无法可靠地到达您的变体。在开发版本中,当两个块声明相同的组合时会记录警告。