WordPress 插件开发中的命名空间与编码规范

随着 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 审阅本文并提供反馈。

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

请登录后发表评论

    暂无评论内容