社区新闻

重构多区块插件:构建更智能、注册更清晰、扩展更轻松

查看官方原文 ↗ 发布于

我构建的区块越多,就越希望有一个不碍事的插件结构。我不想每次添加新内容时都重新思考文件夹结构、重写相同的注册逻辑,或者与构建过程作斗争。

如何构建多区块插件中,我分享了一个在单个插件中管理多个区块的简单基础。该指南侧重于核心概念,如组织文件、注册区块以及快速让一切运行起来,采用的构建策略是将所有内容打包到一个文件中,这对于CDN交付很有效,但并未反映单个区块在WordPress中理想加载的方式。

本文基于该方法,结合实际使用和反馈,将其精炼成更强大的方案。我将逐步创建一个可扩展的设置,支持静态、动态和交互式区块,分离的全局资源,编码标准,以及一个随着插件增长仍易于管理的模块化结构。

前提条件

本文假设你已有一个运行WordPress的本地开发环境,可以通过WordPress Studiowp-env或使用官方WordPress镜像的自定义Docker容器。

你还需要最新版本的Node.js和npm来使用@wordpress/create-block

要查看所需版本:

  • 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目录内运行以下命令,我创建一个静态区块和一个动态区块:

// 创建静态区块
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

构建完成后,我可以在区块插入器小工具部分下找到列出的SliderBanner区块。

区块插入器中显示的静态和动态区块。

添加交互式区块

现在我已经添加了静态和动态区块,下一步是添加一个交互式区块。交互式区块的构建方式略有不同,需要对注册函数和构建过程进行一些更新才能正常工作。

创建交互式区块

与动态区块不同,交互式区块不使用--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中的buildstart命令以包含--experimental-modules标志。这确保脚本正确编译:

// 更新后的构建命令
"build": "wp-scripts build --experimental-modules --blocks-manifest"

// 更新后的启动命令
"start": "wp-scripts start --experimental-modules --blocks-manifest"

测试三种区块类型

所有三种区块类型就位后,我运行:npm run build

构建完成后,我可以在区块插入器小工具部分下看到列出的SliderBannerToggle区块。

区块插入器中显示的交互式区块。

加载额外资源

这个插件不仅仅是注册区块。区块编辑器提供了很大的灵活性,我经常希望包含超越单个区块的增强功能——例如注册区块变体、定义样式选项或向编辑器添加上下文工具。

我编译两个独立的脚本:一个用于编辑器,一个用于前端。它们位于单个区块文件夹之外,并提供一种集中管理跨多个区块功能的方式。每个脚本都有一个匹配的.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交互式区块系统的兼容性。

结论

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

这种方法是实际使用、迭代和社区反馈的结果。它足够灵活以支持自定义工作流,也足够强大以在插件增长时保持其组织性。