重构多区块插件:更高效地构建、更清晰地注册、更轻松地扩展

开发的区块越多,我就越希望插件的结构不要成为阻碍。我不想每添加一个新功能,都重新思考目录结构、改写同样的注册逻辑,或者与构建流程较劲。

在如何构建多区块插件一文中,我介绍了在一个插件中管理多个区块的简单基础方案。那篇指南着重讲解文件组织、区块注册以及快速让插件运转起来等核心概念;它采用将所有内容打包为单个文件的构建策略。这种方式适合通过CDN分发,却没有体现WordPress中单个区块理想的加载方式。

本文在上述方案的基础上,结合实际使用经验与反馈,将其改进为更强大的结构。我会介绍如何创建可扩展的配置,支持静态区块、动态区块和交互式区块,分离全局资源,兼顾编码规范,并通过模块化结构让插件不断增长时仍然易于管理。

前置条件

本文假定你已有运行WordPress的本地开发环境,可以使用WordPress Studio、wp-env,也可以使用官方WordPress镜像创建自定义Docker容器。

使用@wordpress/create-block还需要较新的Node.js和npm。

查看所需版本:

npm view @wordpress/create-block engines

检查当前环境:

node -v
npm -v

如果系统版本低于要求,可以使用nvm更新:

nvm install 20
nvm 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目录中运行以下命令,分别创建一个静态区块和一个动态区块:

// Create a static block
npx @wordpress/create-block@latest slider --textdomain advanced-multi-block --no-plugin

// Create a dynamic block
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+: one-call convenience.
   if ( function_exists( 'wp_register_block_types_from_metadata_collection' ) ) {
       wp_register_block_types_from_metadata_collection( $build_dir, $manifest );
       return;
   }
   // WP 6.7: index the collection, then loop and register each block from metadata.
   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: no collection APIs; just loop the manifest directly.
   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。

构建完成后,便能在区块插入器的“小工具”(Widgets)分组中找到Slider和Banner区块。

原文截图:区块插入器中显示一个静态区块和一个动态区块
区块插入器中的静态区块与动态区块(原文截图)。

添加交互式区块

添加静态区块和动态区块后,下一步是加入交互式区块。交互式区块的构建方式略有不同,需要对注册函数和构建流程做一些调整才能正常工作。

创建交互式区块

与动态区块不同,交互式区块不使用--variant参数,而是使用--template选项指向WordPress提供的起始模板。这样会生成客户端交互式区块所需的文件。

在src/blocks中运行:

// Create an interactive block
npx @wordpress/create-block@latest toggle --textdomain advanced-multi-block --template @wordpress/create-block-interactive-template --no-plugin

修改构建流程

交互式区块还需要对构建配置做一个小改动。我在package.json中的build和start命令里加入--experimental-modules参数,确保脚本能够正确编译:

// Updated build command
"build": "wp-scripts build --experimental-modules --blocks-manifest"

// Updated start command
"start": "wp-scripts start --experimental-modules --blocks-manifest"

测试三种区块类型

三种区块都就绪后,我运行npm run build。

构建完成后,便能在区块插入器的“小工具”(Widgets)分组中看到Slider、Banner和Toggle区块。

原文截图:区块插入器中显示交互式区块
区块插入器中的交互式区块(原文截图)。

加载额外资源

这个插件不只是注册区块。区块编辑器提供了很大的灵活性,我经常希望加入超越单个区块的增强功能,例如注册区块变体、定义样式选项,或者为编辑器添加与当前上下文相关的工具。

我编译两个独立脚本:一个用于编辑器,另一个用于前端。它们放在各区块目录之外,为跨多个区块的功能提供集中管理方式。每个脚本都有配套的.asset.php文件,在构建时自动处理依赖与版本。

添加资源加载类

为了注册这些共享资源,我为每个脚本创建一个简单的加载函数,分别用于区块编辑器与前端。这些函数独立于区块注册逻辑,有助于在插件持续演进时维持模块化结构。

我将它们放在functions.php文件中,位于区块注册函数之后:

/**
* Enqueues the block assets for the editor
*/
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' );

/**
* Enqueues the block assets for the frontend
*/
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的文件。区块编辑器启用时,该文件会被编译并加载到编辑器中。

/**
* Block Editor Script Functionality
*
* The following scripts are compiled into a single asset and loaded into the block editor.
*
*/

// import editor scripts here.

前端脚本

我还在src目录中创建名为frontend-script.js的文件,用于前端专属行为。显示需要这些行为的区块或页面时,该文件会被编译并在前端加载。

/**
* Frontend Script Functionality
*
* The following scripts are compiled into a single asset and loaded into the frontend.
*
*/

// import frontend scripts here.

添加Webpack配置文件

为了独立于核心区块构建流程编译全局脚本,我在插件根目录创建自定义Webpack配置文件webpack.config.js。这样可以复用并扩展@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模块输出。使用--experimental-modules参数构建交互式区块时,WordPress会使用这种输出。虽然当前文件主要处理非交互式资源,但包含这份配置可确保兼容现代模块系统。

扩展默认Webpack配置并加入编辑器和前端脚本后,就能在单次流程中同时构建全局资源与区块。这样既保留了模块化组织,也通过moduleConfig确保与WordPress交互式区块系统兼容。

结语

构建多区块插件不意味着每次都要从零开始。通过改进默认结构、简化注册,并支持不同区块类型和共享资源,可以创建随需求扩展的配置,无论开发的是一个区块还是二十个区块。

这种方法来自实际使用、迭代与社区反馈。它足够灵活,可以支持自定义工作流;也足够强大,能让不断增长的插件保持井然有序。

如果你有问题、想法或改进建议,我很乐意听到。开源工作的美妙之处就在于,我们都在彼此的成果之上继续构建。

感谢@meszarosrob和@milana_cap审阅本文并提供反馈。


原文:Refactoring the multi-block plugin: Build smarter, register cleaner, scale easier,Troy Chaplin,2025年8月27日,WordPress Developer Blog。按转载授权汉化。截图来自原文;示例插件仓库声明采用GPL-2.0-or-later许可证。文中的执行与构建结果为原作者叙述。

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容