重构多区块插件:构建更智能、注册更清晰、扩展更轻松
我构建的区块越多,就越希望有一个不碍事的插件结构。我不想每次添加新内容时都重新思考文件夹结构、重写相同的注册逻辑,或者与构建过程作斗争。
在如何构建多区块插件中,我分享了一个在单个插件中管理多个区块的简单基础。该指南侧重于核心概念,如组织文件、注册区块以及快速让一切运行起来,采用的构建策略是将所有内容打包到一个文件中,这对于CDN交付很有效,但并未反映单个区块在WordPress中理想加载的方式。
本文基于该方法,结合实际使用和反馈,将其精炼成更强大的方案。我将逐步创建一个可扩展的设置,支持静态、动态和交互式区块,分离的全局资源,编码标准,以及一个随着插件增长仍易于管理的模块化结构。
前提条件
本文假设你已有一个运行WordPress的本地开发环境,可以通过WordPress Studio、wp-env或使用官方WordPress镜像的自定义Docker容器。
你还需要最新版本的Node.js和npm来使用@wordpress/create-block。
要查看所需版本:
npm view @wordpress/create-block engines
要检查当前设置:
node -vnpm -v
如果你的系统版本低于要求,可以使用nvm更新:
nvm install 20nvm use 20
这确保了兼容性,并避免了后续构建问题。
如果你想跟随操作或参考工作示例,本文构建的完整插件可在GitHub上获取,本文的每个部分都对应一个分支。
基本插件设置
首先,我将搭建一个新插件,并重构其结构,以清晰、有序的方式支持多个区块。我将使用@wordpress/create-block添加一个静态区块和一个动态区块,每个区块放在自己的文件夹中。我还将更新注册函数,以便新区块被自动识别,无需手动注册每个区块,只需将它们放入正确的文件夹。
创建插件基础
我要做的第一件事是在本地WordPress环境的plugins文件夹中运行npx @wordpress/create-block@latest advanced-multi-block来搭建一个新插件。这将为我设置一个单静态区块插件。
更新插件结构
接下来,我快速重构默认结构,以支持一个组织良好、可随项目增长的多区块插件。
我不再将区块嵌套在单个文件夹中,而是将它们移动到顶层的src/blocks目录。这种设置不仅使区块结构更易于浏览,还为增长留出了空间。随着我后续添加其他全局资源(如全局JavaScript或编辑器样式),从一开始就保持清晰的分离有助于保持整洁和可维护性。
在src目录内,我进行以下更改:
- 删除
src/advanced-multi-block文件夹 - 在
src内创建一个名为blocks的文件夹
创建静态和动态区块
现在我有了一个干净、有组织的结构,可以开始添加区块。我使用@wordpress/create-block并带上--no-plugin标志,这样我可以在现有的目录布局中生成每个区块,而不是创建新的独立插件。
根据区块类型,我还添加--variant标志。为了保持国际化的一致性,我指定一个一致的--textdomain。
通过在src/blocks目录内运行以下命令,我创建一个静态区块和一个动态区块:
// 创建静态区块
npx @wordpress/create-block@latest slider --textdomain advanced-multi-block --no-plugin
// 创建动态区块
npx @wordpress/create-block@latest banner --textdomain advanced-multi-block --no-plugin --variant dynamic
更新区块注册函数
@wordpress/create-block搭建的函数已经为注册多个区块提供了坚实的基础。它定义了一个名为create_block_advanced_multi_block_block_init的函数(为了清晰起见,我将重命名它)。为了支持将所有区块放在src/blocks下的更新文件夹结构,我只需要做一个最小的更改:在三处更新区块路径以包含新的目录结构。
这是该函数的修订版,名称更短:
function register_blocks() {
$build_dir = __DIR__ . '/build/blocks';
$manifest = __DIR__ . '/build/blocks-manifest.php';
// WP 6.8+: 单次调用的便利性。
if ( function_exists( 'wp_register_block_types_from_metadata_collection' ) ) {
wp_register_block_types_from_metadata_collection( $build_dir, $manifest );
return;
}
// WP 6.7: 索引集合,然后循环并从元数据注册每个区块。
if ( function_exists( 'wp_register_block_metadata_collection' ) ) {
wp_register_block_metadata_collection( $build_dir, $manifest );
$manifest_data = require $manifest;
foreach ( array_keys( $manifest_data ) as $block_type ) {
register_block_type_from_metadata( $build_dir . '/' . $block_type );
}
return;
}
// WP 5.5-6.6: 无集合API;直接循环清单。
if ( function_exists( 'register_block_type_from_metadata' ) ) {
$manifest_data = require $manifest;
foreach ( array_keys( $manifest_data ) as $block_type ) {
register_block_type_from_metadata( $build_dir . '/' . $block_type );
}
return;
}
}
add_action( 'init', 'register_blocks' );
通过此设置,可以通过在src/blocks中运行npx create-block命令来添加新区块。清单会自动处理注册,无需更新注册逻辑。
测试基本设置
一切就绪后,我运行:npm run build
构建完成后,我可以在区块插入器的小工具部分下找到列出的Slider和Banner区块。
添加交互式区块
现在我已经添加了静态和动态区块,下一步是添加一个交互式区块。交互式区块的构建方式略有不同,需要对注册函数和构建过程进行一些更新才能正常工作。
创建交互式区块
与动态区块不同,交互式区块不使用--variant标志。相反,我使用--template选项并将其指向WordPress提供的入门模板。这会生成客户端交互式区块所需的文件。
在src/blocks内,我运行以下命令:
// 创建交互式区块
npx @wordpress/create-block@latest toggle --textdomain advanced-multi-block --template @wordpress/create-block-interactive-template --no-plugin
修改构建过程
交互式区块还需要对构建配置进行一个小更改。我更新package.json中的build和start命令以包含--experimental-modules标志。这确保脚本正确编译:
// 更新后的构建命令
"build": "wp-scripts build --experimental-modules --blocks-manifest"
// 更新后的启动命令
"start": "wp-scripts start --experimental-modules --blocks-manifest"
测试三种区块类型
所有三种区块类型就位后,我运行:npm run build
构建完成后,我可以在区块插入器的小工具部分下看到列出的Slider、Banner和Toggle区块。
加载额外资源
这个插件不仅仅是注册区块。区块编辑器提供了很大的灵活性,我经常希望包含超越单个区块的增强功能——例如注册区块变体、定义样式选项或向编辑器添加上下文工具。
我编译两个独立的脚本:一个用于编辑器,一个用于前端。它们位于单个区块文件夹之外,并提供一种集中管理跨多个区块功能的方式。每个脚本都有一个匹配的.asset.php文件,确保在构建过程中自动处理依赖关系和版本控制。
添加加载类
为了注册这些共享资源,我为每个脚本创建一个简单的加载函数——一个用于区块编辑器,一个用于前端。这些与区块注册逻辑分开,有助于在插件演进时保持模块化结构。
我将它们放在functions.php文件中,位于区块注册函数下方:
/**
* 为编辑器加载区块资源
*/
function enqueue_block_assets() {
$asset_file = include plugin_dir_path( __FILE__ ) . 'build/editor-script.asset.php';
wp_enqueue_script(
'editor-script-js',
plugin_dir_url( __FILE__ ) . 'build/editor-script.js',
$asset_file['dependencies'],
$asset_file['version'],
false
);
}
add_action( 'enqueue_block_editor_assets', 'enqueue_block_assets' );
/**
* 为前端加载区块资源
*/
function enqueue_frontend_assets() {
$asset_file = include plugin_dir_path( __FILE__ ) . 'build/frontend-script.asset.php';
wp_enqueue_script(
'frontend-script-js',
plugin_dir_url( __FILE__ ) . 'build/frontend-script.js',
$asset_file['dependencies'],
$asset_file['version'],
true
);
}
add_action( 'wp_enqueue_scripts', 'enqueue_frontend_assets' );
添加脚本资源
编辑器脚本
我在src目录中创建一个名为editor-script.js的文件。这将被编译并加载到区块编辑器(只要它处于活动状态)。
<em>/**
* 区块编辑器脚本功能
*
* 以下脚本被编译成单个资源并加载到区块编辑器中。
*
*/
// 在此处导入编辑器脚本。</em>
前端脚本
我还在src目录中创建一个名为frontend-script.js的文件,用于前端特定行为。这将被编译并加载到前端,当显示需要它的区块或页面时。
<em>/**
* 前端脚本功能
*
* 以下脚本被编译成单个资源并加载到前端。
*
*/
// 在此处导入前端脚本。</em>
添加Webpack文件
为了将全局脚本与核心区块构建过程分开构建,我在插件根目录创建一个名为webpack.config.js的自定义Webpack配置文件。这允许我重用和扩展@wordpress/scripts提供的默认配置,而不会干扰WordPress构建交互式区块的方式。
文件内容如下:
const [ scriptConfig, moduleConfig, ] = require('@wordpress/scripts/config/webpack.config');
const path = require('path');
module.exports = [
{
...scriptConfig,
entry: {
...scriptConfig.entry(),
'editor-script': path.resolve(__dirname, 'src/editor-script.js'),
'frontend-script': path.resolve(__dirname, 'src/frontend-script.js'),
},
},
moduleConfig,
];
此文件导出两个配置的数组:
- 第一个(
scriptConfig)是WordPress用于传统(非交互式)脚本的标准Webpack配置。在这里,我通过添加两个新的入口点来扩展它:一个用于编辑器端JavaScript,一个用于前端行为。这些脚本将被编译到build目录中,并具有可预测的文件名。 - 第二个(
moduleConfig)是支持ES模块输出所必需的,WordPress在使用--experimental-modules标志构建交互式区块时会使用它。包含此配置可确保与现代模块系统的兼容性,即使此特定文件专注于构建非交互式资源。
通过扩展默认的Webpack配置以包含编辑器和前端脚本,我可以在单个过程中将全局资源与区块构建一起打包。这使一切保持模块化,同时通过moduleConfig确保与WordPress交互式区块系统的兼容性。
结论
构建多区块插件并不意味着每次都要从头开始。通过优化默认结构、简化注册过程以及支持不同的区块类型和共享资源,你可以创建一个能够随需求扩展的设置——无论你构建一个区块还是二十个。
这种方法是实际使用、迭代和社区反馈的结果。它足够灵活以支持自定义工作流,也足够强大以在插件增长时保持其组织性。