WordPress 中的区块通常打包在插件中,并使用 block.json 元数据在服务器端和客户端进行注册。

虽然可以在客户端单独注册区块,但最佳实践强烈建议在服务器端和客户端都进行注册。这种双重注册对于启用动态渲染、区块支持、区块钩子和样式变体等服务器端功能至关重要。如果没有服务器端注册,这些功能将无法正常工作。

例如,如果您希望一个区块 通过 theme.json 进行样式设置,则必须在服务器端对其进行注册。否则,该区块将无法识别或应用 theme.json 中为其分配的样式。

下图详细介绍了区块的注册过程。

打开区块注册流程图

使用 PHP 注册区块(服务器端)

服务器端的区块注册发生在主插件 PHP 文件中,钩挂在 init。WordPress 为此提供了几个函数,具体取决于您的需求以及您针对的最低 WordPress 版本。

使用元数据集合一次性注册所有区块(推荐)

自 WordPress 6.8 以来,注册区块的推荐方法是 wp_register_block_types_from_metadata_collection()。此函数在一个调用中注册 blocks-manifest.php 文件中定义的所有区块类型,从而消除了对单独的 register_block_type() 调用的需求。

blocks-manifest.php 文件由 wp-scripts build-blocks-manifest 命令自动生成(或者通过向 build 和 start 命令传递 --blocks-manifest 标志)。它将项目中所有 block.json 文件中的元数据编译到一个 PHP 文件中。

function my_plugin_register_blocks() {
    wp_register_block_types_from_metadata_collection(
        __DIR__ . '/build',
        __DIR__ . '/build/blocks-manifest.php'
    );
}
add_action( 'init', 'my_plugin_register_blocks' );

这是 create-block 脚手架工具所使用的方法。它通过避免从磁盘读取多个 block.json 文件来提高性能,并简化了插件的注册代码——特别是对于具有多个区块的插件。

wp_register_block_types_from_metadata_collection() 需要 WordPress 6.8 或更高版本。有关更多详细信息,请参阅 WordPress 6.8 开发说明。

单独注册元数据集合(WordPress 6.7+)

如果您需要更精确地控制单个区块的注册方式(例如,为每个区块传递不同的 $args),您可以使用 wp_register_block_metadata_collection() 先注册清单,然后对每个区块单独调用 register_block_type()。WordPress 将从已加载的清单中读取每个区块的元数据,而不是从磁盘读取。

function my_plugin_register_blocks() {
    wp_register_block_metadata_collection(
        __DIR__ . '/build',
        __DIR__ . '/build/blocks-manifest.php'
    );

    register_block_type( __DIR__ . '/build/block-one' );
    register_block_type( __DIR__ . '/build/block-two', array(
        'render_callback' => 'my_plugin_render_block_two',
    ) );
}
add_action( 'init', 'my_plugin_register_blocks' );
wp_register_block_metadata_collection() 需要 WordPress 6.7 或更高版本。有关更多详细信息,请参阅 WordPress 6.7 开发说明。

使用 register_block_type() 注册单个区块

register_block_type() 函数通过从 block.json 文件读取元数据来注册单个区块类型。这仍然是一种有效的方法,特别是对于只有一个区块的插件或针对低于 6.7 版本的 WordPress 时。

此函数主要使用两个参数:

  • $block_type (string): 包含 block.json 文件的目录路径,或者如果文件名不同则为元数据文件的完整路径。
  • $args (array): 用于区块类型的额外参数的可选数组。这可以包括 render_callback 作为 block.json 中 render 属性的替代方案。

在开发过程中,block.json 文件通常从 src(源)目录移动到 build 目录,作为编译代码的一部分。因此,在注册区块时,请确保 $block_type 路径指向 build 目录中的 block.json 文件。

register_block_type() 函数在成功时返回注册的区块类型 (WP_Block_Type),或在失败时返回 false。以下是使用 render_callback 的简单示例。

register_block_type(
    __DIR__ . '/build',
    array(
        'render_callback' => 'render_block_core_notice',
    )
);

这是一个更完整的示例,包括 init 钩子。

function minimal_block_ca6eda___register_block() {
    register_block_type( __DIR__ . '/build' );
}
add_action( 'init', 'minimal_block_ca6eda___register_block' );

参见 完整区块示例 的 上述代码

具有自动注册的纯 PHP 区块

对于只需要服务器端渲染的区块,您可以使用 autoRegister 标志和 render_callback 在 PHP 中专门注册它们。这些区块会自动出现在编辑器中,无需任何 JavaScript 注册或客户端代码,并使用 动态渲染。

register_block_type( 'my-plugin/server-block', array(
    'render_callback' => function( $attributes ) {
        $wrapper_attributes = get_block_wrapper_attributes();

        return sprintf(
            '<div %1$s>Server content</div>',
            $wrapper_attributes
        );
    },
    'supports' => array(
        'autoRegister' => true,
        'color' => array(
            'background' => true,
        ),
    ),
) );

使用 JavaScript 注册区块(客户端)

当区块已在服务器端注册,并且不使用 纯 PHP 自动注册区块 时,您只需使用 @wordpress/blocks 包中的 registerBlockType 方法在 JavaScript 中注册客户端设置。您只需确保使用与区块的 block.json 文件中定义的相同的区块名称即可。示例如下:

import { registerBlockType } from '@wordpress/blocks';

registerBlockType( 'my-plugin/notice', {
    edit: Edit,
    // ...其他客户端设置
} );

虽然通常建议使用 PHP 在服务器端注册区块以获得 “使用元数据文件的优点” 部分中概述的好处,但您可以选择仅在客户端注册区块。registerBlockType 方法允许您使用元数据注册区块类型。

该函数接受两个参数:

  • blockNameOrMetadata (string|Object): 这可以是区块类型的名称(字符串)或包含区块元数据的对象,通常从 block.json 文件加载。
  • settings (Object): 这是包含区块客户端设置的对象。
您可以使用构建流程(例如由 wp-scripts 提供的那个)直接将 block.json 文件(或任何其他 .json 文件)的内容导入到您的 JavaScript 文件中。

作为第二个参数传递的 settings 对象包含许多属性,但以下两个最为重要:

  • edit: 在编辑器中用于我们块的 React 组件。
  • save: 返回保存至数据库的静态 HTML 标记的函数。

registerBlockType() 函数在成功时返回已注册的块类型 (WPBlock),或在失败时返回 undefined。示例如下:

import { registerBlockType } from '@wordpress/blocks';
import { useBlockProps } from '@wordpress/block-editor';
import metadata from './block.json';

const Edit = () => <p { ...useBlockProps() }>Hello World - Block Editor</p>;
const save = () => <p { ...useBlockProps.save() }>Hello World - Frontend</p>;

registerBlockType( metadata.name, {
    edit: Edit,
    save,
} );

参见 完整块示例 中的 上述代码

其他资源