随着 WordPress 项目日益复杂,组织代码库变得至关重要。无论开发插件、主题还是区块库,清晰且可扩展的架构都能加快开发、降低新人上手难度,并显著减轻长期维护的负担。
在 重构多区块插件:更高效地构建、更清晰地注册、更轻松地扩展 中,我介绍了如何在一个插件里建立灵活的结构,管理多个静态、动态和交互式区块。那套结构也是本文的基础。
这里进一步引入 PHP 命名空间、Composer 自动加载,以及 JavaScript、CSS 和 PHP 的统一编码规范。这些不只是最佳实践,更是项目规模扩大时维持质量、扩展代码的具体方法。
我们将依次介绍:
-
使用 Composer 设置 PSR-4 自动加载
-
把插件功能组织为可复用、职责明确的类
-
利用自动化代码检查和格式化工具保持统一风格
这套流程对个人开发者足够灵活,也足以支持大型项目中的团队协作。
目录
前提条件
本文建立在 完善多区块插件 的基础上。如果已按那篇指南搭建包含静态、动态和交互式区块的插件脚手架,就可以继续下一步。
想跳过初始设置?本文完成的插件已 发布在 GitHub 上,每节内容都有对应分支。
想跟着实践,但不想自己搭建多区块起点?可以克隆 多区块插件仓库,运行 npm install,然后从那里开始。
两种方式都能提供可直接使用的起点,并配好命名空间、Composer 自动加载和代码检查。
命名空间与类
插件逐渐扩大时,必须让代码有序且易于管理。我使用 PHP 命名空间,并按功能拆分类,让每一部分都有明确目的。这样既能避免名称冲突,也便于扩展和维护代码库。
Composer 与自动加载
为简化类的加载,我使用 Composer 的 PSR-4 自动加载。不必手动包含文件,Composer 会根据所定义的命名空间和目录结构自动加载类。
这套结构使用 Advanced_Multi_Block 命名空间聚合插件相关类。它类似一个前缀,既避免命名冲突,也把相关内容限制在插件范围内。
首先在插件根目录创建 composer.json 文件,并加入以下内容:
复制 JSON 配置时,请使用普通空格或 Tab 缩进,不要使用不换行空格(U+00A0);下面的配置示例已采用普通空格缩进。
{
"name": "multi-block/namespacing-coding-standards",
"description": "An advanced multi block plugin with custom functionality.",
"type": "wordpress-plugin",
"license": "GPL-2.0-or-later",
"autoload": {
"psr-4": {
"Advanced_Multi_Block\\": "Functions/"
}
}
}
然后运行 composer install。这会生成 vendor 目录和 autoloader,主插件文件可以引入它。
文件与类
自动加载就绪后,我把所有基于类的 PHP 文件放到插件内的 Functions 目录。统一存放使插件扩大后仍便于管理。
每个类处理特定功能,均归于 Advanced_Multi_Block 命名空间。这种结构让职责清晰,并避免代码库中的名称冲突。
插件路径(Plugin Paths)
这个类提供获取插件基础路径和URL的辅助方法。我在整个插件中使用它,避免重复逻辑或依赖硬编码值。
在 Functions 目录中创建 Plugin_Paths.php,粘贴以下代码:
<?php
namespace Advanced_Multi_Block;
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
class Plugin_Paths {
public static function plugin_url() {
return plugin_dir_url( dirname( __FILE__ ) );
}
public static function plugin_path() {
return plugin_dir_path( dirname( __FILE__ ) );
}
}
注册区块(Register Blocks)
这个类负责查找和注册区块。我在构造函数中挂接 init 动作,并通过 Plugin_Paths 获取插件路径。
register_blocks() 方法遍历各个区块目录,检查 block.json 文件并注册区块。如果区块包含 viewScriptModule 字段,就会添加过滤器,让 WordPress 加载交互式区块需要的资源。
在 Functions 目录中创建 Register_Blocks.php,粘贴以下代码:
<?php
namespace Advanced_Multi_Block;
use Advanced_Multi_Block\Plugin_Paths;
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
class Register_Blocks {
public function __construct() {
add_action( 'init', array( $this, 'register_blocks' ) );
}
public function register_blocks() {
if ( function_exists( 'wp_register_block_types_from_metadata_collection' ) ) {
wp_register_block_types_from_metadata_collection( Plugin_Paths::plugin_path() . 'build/blocks', Plugin_Paths::plugin_path() . '/build/blocks-manifest.php' );
return;
}
if ( function_exists( 'wp_register_block_metadata_collection' ) ) {
wp_register_block_metadata_collection( Plugin_Paths::plugin_path() . 'build/blocks', Plugin_Paths::plugin_path() . '/build/blocks-manifest.php' );
}
$manifest_data = include Plugin_Paths::plugin_path() . 'build/blocks-manifest.php';
foreach ( array_keys( $manifest_data ) as $block_type ) {
register_block_type( Plugin_Paths::plugin_path() . "build/blocks/{$block_type}" );
}
}
}
加载资源(Enqueue)
这个类注册两个全局资源入口:一个面向编辑器,另一个面向前台。它们独立于区块专用脚本,适合区块变体、编辑器界面增强,或跨多个区块的全局行为。
每个脚本都使用对应的 .asset.php 文件,以便正确处理依赖和版本。我通过 Plugin_Paths 辅助类引用正确路径和URL。
在 Functions 目录中创建名为 Enqueues.php 的文件,加入以下代码:
<?php
namespace Advanced_Multi_Block;
use Advanced_Multi_Block\Plugin_Paths;
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
class Enqueues {
public function __construct() {
add_action( 'enqueue_block_editor_assets', array( $this, 'enqueue_block_assets' ) );
add_action( 'wp_enqueue_scripts', array( $this, 'enqueue_frontend_assets' ) );
}
/**
* Enqueues the block assets for the editor
*/
public function enqueue_block_assets() {
$asset_file = include Plugin_Paths::plugin_path() . 'build/editor-script.asset.php';
wp_enqueue_script(
'editor-script-js',
Plugin_Paths::plugin_url() . 'build/editor-script.js',
$asset_file['dependencies'],
$asset_file['version'],
false
);
}
/**
* Enqueues the block assets for the frontend
*/
public function enqueue_frontend_assets() {
$asset_file = include Plugin_Paths::plugin_path() . 'build/frontend-script.asset.php';
wp_enqueue_script(
'frontend-script-js',
Plugin_Paths::plugin_url() . 'build/frontend-script.js',
$asset_file['dependencies'],
$asset_file['version'],
true
);
}
}
更新主插件文件
类和自动加载设置完成后,更新主插件文件以正确加载它们。首先检查 Composer 自动加载文件并引入,然后实例化核心类,把它们的功能注册到 WordPress。
这让主文件保持简洁且聚焦,同时由每个类承担自己的职责。
<?php
if (! defined('ABSPATH') ) {
exit;
}
// Include Composer's autoload file.
if ( file_exists( plugin_dir_path( __FILE__ ) . 'vendor/autoload.php' ) ) {
require_once plugin_dir_path( __FILE__ ) . 'vendor/autoload.php';
} else {
wp_trigger_error( 'Advanced Multi Block Plugin: Composer autoload file not found. Please run `composer install`.', E_USER_ERROR );
return;
}
// Instantiate the classes.
$advanced_multi_block_classes = array(
\Advanced_Multi_Block\Plugin_Paths::class,
\Advanced_Multi_Block\Register_Blocks::class,
\Advanced_Multi_Block\Enqueues::class,
);
foreach ( $advanced_multi_block_classes as $advanced_multi_block_class ) {
new $advanced_multi_block_class();
}
编码规范
保持代码一致,是改善协作和长期可维护性最直接的方法之一,特别适用于大型或共享代码库。本节使用 WordPress 推荐的工具,为插件配置 JavaScript、CSS 和 PHP 代码检查与格式化。
提示:这不是一套严格不变的规则,而是可用的起点。可以直接使用,也可以按团队偏好调整。
为 JavaScript 加入代码检查
为了让 JavaScript 文件保持一致,我采用 WordPress 推荐配置,用 ESLint 进行代码检查,用 Prettier 格式化。
安装所需的开发依赖:
npm install --save-dev @wordpress/eslint-plugin eslint-config-prettier @wordpress/prettier-config eslint-config-prettier
然后在插件根目录创建 .eslintrc.json,使用以下配置。它继承 WordPress ESLint 插件的推荐规则,并设置环境及解析器选项:
{
"extends": ["plugin:@wordpress/eslint-plugin/recommended"],
"env": {
"browser": true,
"es6": true,
"jquery": true
},
"parserOptions": {
"requireConfigFile": false,
"ecmaVersion": 2021,
"sourceType": "module"
},
"rules": {
"@wordpress/no-global-active-element": "warn",
"@wordpress/no-unsafe-wp-apis": "warn"
}
}
再添加 .eslintignore,避免检查编译产物和第三方文件:
/build/
/vendor/
/node_modules/
*.css
*.scss
为处理代码格式,创建 .prettierrc,写入偏好的样式规则:
{
"tabWidth": 4,
"useTabs": true,
"printWidth": 100,
"singleQuote": true,
"trailingComma": "es5",
"bracketSpacing": true,
"arrowParens": "avoid",
"semi": true,
"bracketSameLine": false,
"jsxSingleQuote": false,
"jsxBracketSameLine": false
}
另外创建 .prettierignore,排除生成目录和依赖目录:
build
node_modules
vendor
在 package.json 中加入以下脚本,用于检查和格式化 JS 文件。这些配置替换已有的 lint:js 和 format:js 条目:
"lint:js": "wp-scripts lint-js --max-warnings=0",
"format:js": "wp-scripts lint-js --fix",
现在可以运行 npm run lint:js 或 npm run format:js,检查和修复 JavaScript 文件。
为 CSS 加入代码检查
为了统一 SCSS 文件并发现潜在问题,我使用 WordPress 推荐的 SCSS 配置设置 Stylelint。
安装所需的开发依赖:
npm install --save-dev @wordpress/stylelint-config stylelint stylelint-scss
然后在插件根目录创建 .stylelintrc.json,使用以下配置。它继承 WordPress 的 SCSS 规则,并禁用几条规则以适配我偏好的风格:
{
"extends": ["@wordpress/stylelint-config/scss"],
"rules": {
"at-rule-no-unknown": null,
"selector-class-pattern": null,
"scss/at-rule-no-unknown": true
}
}
另外创建 .stylelintignore,排除编译产物和第三方文件:
build/
node_modules/
vendor/
*.min.css
*.min.scss
在 package.json 中加入以下脚本,用于检查和修复 SCSS 文件。这些配置替换已有的 lint:css 和 format:css 条目:
"lint:css": "stylelint \"**/*.scss\" --max-warnings=0",
"format:css": "stylelint \"**/*.scss\" --fix",
现在可以运行 npm run lint:css 或 npm run format:css,检查和修复 CSS 文件。
为 PHP 加入代码检查
为了执行 WordPress 编码规范,我使用 PHP_CodeSniffer 和 WordPress 编码规范(WPCS) 规则集。它帮助发现常见问题,并保持整个插件的一致性。
首先在插件根目录创建 phpcs.xml.dist,加入以下配置:
<?xml version="1.0"?>
<ruleset name="WordPress Plugin Coding Standards">
<description>A custom set of rules to check for a WordPress plugin</description>
<!-- What to scan -->
<file>.</file>
<exclude-pattern>/build/</exclude-pattern>
<exclude-pattern>/node_modules/</exclude-pattern>
<exclude-pattern>/vendor/</exclude-pattern>
<exclude-pattern>src/blocks-manifest.php</exclude-pattern>
<exclude-pattern>build/*.asset.php</exclude-pattern>
<!-- How to scan -->
<arg value="sp"/>
<arg name="basepath" value="."/>
<arg name="colors"/>
<arg name="extensions" value="php"/>
<arg name="parallel" value="4"/>
<!-- Rules: WordPress Coding Standards -->
<config name="minimum_supported_wp_version" value="6.6"/>
<rule ref="WordPress">
<exclude name="Generic.Arrays.DisallowShortArraySyntax"/>
<exclude name="Generic.Functions.CallTimePassByReference"/>
<exclude name="WordPress.PHP.YodaConditions.NotYoda"/>
</rule>
<rule ref="WordPress.Arrays.MultipleStatementAlignment">
<properties>
<property name="maxColumn" value="80"/>
</properties>
</rule>
<rule ref="WordPress.NamingConventions.PrefixAllGlobals">
<properties>
<property name="prefixes" type="array">
<element value="Advanced_Multi_Block"/>
</property>
</properties>
</rule>
<rule ref="WordPress.WP.I18n">
<properties>
<property name="text_domain" type="array">
<element value="advanced-multi-block"/>
</property>
</properties>
</rule>
</ruleset>
这是基于官方 WordPress 规范的起点。如果要进一步自定义,建议阅读完整的 WPCS 文档。
接着更新 composer.json,安装所需依赖,并定义代码检查与格式化脚本:
{
"name": "wp-dev-blog/refactor-multi-block-plugin",
"description": "An advanced multi block plugin with custom functionality.",
"type": "wordpress-plugin",
"license": "GPL-2.0-or-later",
"autoload": {
"psr-4": {
"Advanced_Multi_Block\\": "Functions/"
}
},
"require-dev": {
"wp-coding-standards/wpcs": "^3.1"
},
"config": {
"allow-plugins": {
"dealerdirect/phpcodesniffer-composer-installer": true
}
},
"scripts": {
"format": "./vendor/bin/phpcbf --report-summary --report-source || true",
"lint": "./vendor/bin/phpcs"
}
}
然后运行 composer update,安装新增包。
在 package.json 中加入以下脚本,用于检查和修复 PHP 文件。这些配置替换已有的 lint:php 和 format:php 条目:
"lint:php": "composer run lint",
"format:php": "phpcbf --standard=phpcs.xml.dist -v",
现在可以运行 npm run lint:php 或 npm run format:php,检查和修复 PHP 文件。
统一命令
为让所有环境中的代码检查命令保持一致,我在 package.json 中加入以下内容:
"lint": "npm run lint:js && npm run lint:php && npm run lint:css",
"format": "npm run format:js && npm run format:php && npm run format:css",
使用 Composer 自动加载
在 composer.json 中定义 Composer 的 PSR-4 自动加载后,不必为每个类手动编写 require。主插件文件加载生成的 vendor/autoload.php,其余由 Composer 处理。
每次添加、移动或重命名类后,运行 composer dump-autoload。
这会刷新类映射,让新文件和更新后的文件可被发现。这个简单但重要的习惯,可防止“class not found”错误,并让插件结构与命名空间保持同步。
结语
命名空间、Composer 自动加载和清晰的编码规范,共同构成可长期使用的基础。代码更容易理解、测试和扩展,并能在插件或主题不断扩大时保持这些优点。
这套结构的每个组成部分都有作用:
-
命名空间与类分离职责、减少冲突
-
Composer 自动加载消除重复样板代码,便于扩展
-
代码检查和格式化工具让整个技术栈中的代码保持整洁一致
这些实践能够提升开发把握,避免代码库演进时陷入低效。无论为客户、团队还是自己开发,都有助于保持项目可维护、高效且适于协作。
欢迎提供反馈。如果有建议、疑问,或者想分享组织项目的方法,我很乐意听到。
感谢 @meszarosrob 和 @milana_cap 审阅本文并提供反馈。











暂无评论内容