Gutenberg 插件 PHP 代码库开发指南:lib 目录结构、命名约定与 WordPress Core 同步机制
Gutenberg 插件 PHP 代码库开发指南lib 目录结构、命名约定与 WordPress Core 同步机制【免费下载链接】gutenbergThe Block Editor project for WordPress and beyond. Plugin is available from the official repository.项目地址: https://gitcode.com/GitHub_Trending/gu/gutenberg本篇技术指南面向在 Gutenberg 插件中贡献 PHP 代码的开发者系统讲解lib目录的文件组织规范、gutenberg与wp前缀的选用原则、避免重复声明的防护写法、按功能聚合代码的实践以及插件与 WordPress Core 之间的 backport反向移植同步流程。读完本文你将掌握在 Gutenberg 仓库 lib 下正确放置与命名 PHP 文件、编写可安全合并进 Core 的代码、并通过 backport-changelog 记录 Core PR 的完整方法论。文档定位与适用人群lib/README.md 是 Gutenberg 插件 PHP 代码的权威开发指南服务对象是向 Gutenberg 插件贡献 PHP 代码的开发者内容围绕lib目录展开。Gutenberg 插件持续增强既有功能、孵化新特性一部分功能在稳定后随 WordPress 大版本发布合并进 CoreWordPress 源码另一部分长期留在插件内还有一部分会随最低支持 WordPress 版本的上调而被移除。因此一致的命名与目录结构是插件与 Core 之间高频同步的前提——它既能避免命名冲突又能把属于某个 WordPress 版本的代码隔离存放。指南本身定位为指引而非强制规范如果你对命名或新 PHP 文件的位置拿不准文档建议直接在 GitHub 上联系其他贡献者或在 WordPress Slack 的#core-editor频道提问。lib 目录的文件结构三分类 根目录常青代码为了让贡献者一眼识别哪些功能应合并进 Core、哪些可以被删除Gutenberg 对lib目录的 PHP 代码采用了如下结构对照真实仓库目录 liblib/experimental —— 实验性特性仅存在于插件中的实验性功能不应合并进 Core。从真实目录看该目录内容非常丰富例如 lib/experimental/collaboration实时协作、lib/experimental/dashboard-widgets仪表盘组件、lib/experimental/knowledge指南/知识库、lib/experimental/media-editor、lib/experimental/theme-preview 等子模块以及 blocks.php、script-modules.php、class-gutenberg-hierarchical-sort.php 等单文件。值得注意的是很多实验特性是通过开关按需加载的。在 lib/load.php 中可以看到诸如gutenberg-extensible-site-editor、gutenberg-media-editor、gutenberg-workflow-palette、gutenberg-dashboard-widgets、gutenberg-guidelines等实验都会先调用gutenberg_is_experiment_enabled()检查选项值再require对应文件而实验开关的启用界面则由 lib/init.php 中以add_submenu_page()挂载的 Experiments 设置页提供渲染回调定义于 lib/experimental/experiments/load.php。lib/compat/wordpress-X.Y —— 面向特定 Core 版本的兼容层此类目录存放计划在未来的 X.Y 版本合并进 Core 的稳定特性或已在 X.Y 版本合并进 Core、但为了在旧版 WordPress 上运行插件而保留的向后兼容代码。当前仓库中有两个版本目录lib/compat/wordpress-7.1 与 lib/compat/wordpress-7.2。从 lib/load.php 可以看到wordpress-7.1下的view-config-api.php、class-gutenberg-rest-attachments-controller-7-1.php、block-bindings.php、query-block.php、block-comments.php等以及wordpress-7.2下的class-gutenberg-rest-templates-controller-7-2.php、view-config-api.php等文件都只在 REST 控制器上下文class_exists( WP_REST_Controller )中加载。这种按版本分目录的做法让哪个文件属于哪个 WordPress 版本一目了然。lib/compat/plugin —— 面向插件消费者的向后兼容存放为插件消费者提供的向后兼容特性这些文件不需要合并进 Core且应当有明确的移除时间表。当前 lib/compat/plugin 包含edit-site-routes-backwards-compat.php、fonts.php、connectors.php、style-state-aliases.php四个文件从 lib/load.php 中可以看到它们被集中加载。以 lib/compat/plugin/fonts.php 为例文件头注释明确写着core-merge: Do not merge this function不要合并此函数因为gutenberg_before_delete_font_face()只负责删除 Gutenberg 专用的wp-content/fonts目录下的字体文件——这正是compat/plugin 不应进 Core、应规划移除的活样本。lib 根目录 —— 常青evergreen代码位于/lib根目录的文件通常被视为evergreen常青代码它们既对插件正常运行至关重要又更新过于频繁以致按 WordPress 版本做版本隔离并不现实。这类代码的改动会根据需要随时合并进 Core。真实仓库根目录下的 block-editor-settings.php、blocks.php、script-loader.php、global-styles-and-settings.php、class-wp-theme-json-gutenberg.php 等均属此类由 lib/load.php 集中加载。命名最佳实践gutenberg前缀 vswp前缀为避免与 WordPress Core 及其他插件产生命名冲突Gutenberg 在大量 PHP 类名和函数名中使用gutenberg标识例如WP_Theme_JSON_Gutenberg和gutenberg_get_block_editor_settings后者真实定义于 lib/block-editor-settings.php。常青代码优先使用gutenberg前缀功能无处不在、且持续更新的常青代码尤其应该使用gutenberg前缀。文档以WP_Theme_JSON_Gutenberg为例该类控制 Gutenberg 处理与输出全局样式的方式其方法被大量调用。真实源码印证了这一点——lib/class-wp-theme-json-gutenberg.php 中的类注释明确说明它是解析 theme.json 规范结构的底层类同时提示扩展者应改用gutenberg_get_global_settings、gutenberg_get_global_styles、gutenberg_get_global_stylesheet等高层 API。对于此类代码即使站点运行在旧版 WordPress 上插件用户也应始终使用最新版本。一个标准的gutenberg前缀函数示例/** * Returns something useful. * * since 6.2.0 Updates to something even more useful. * since 6.3.0 Now more useful than ever. * * return string Something useful. */ function gutenberg_get_something_useful() { // ... }移植进 Core重命名为wp_/WP_当把新函数移植进 Core 时函数必须改用wp_前缀、类必须改用WP_前缀/** * Returns something useful. * * since 6.2.0 Updates to something even more useful. * since 6.3.0 Now more useful than ever. * * return string Something useful. */ function wp_get_something_useful() { // ... }插件中稳定、且预期在近期原样合并进 Core的代码可以直接使用wp_函数前缀或WP_类前缀。避免重复声明function_exists()与class_exists()包装使用wp_前缀时必须确保 Gutenberg 与 WordPress Core 之间不会出现函数或类的重复声明。除了用代码库搜索确认新名字唯一之外还应当用function_exists()与class_exists()检查做包装使代码在合并进 Core 之前、或插件运行在旧版 WordPress 上时都能正常执行if ( ! function_exists( wp_a_new_and_stable_feature ) ) { /** * A very new and stable feature. * * return string Something useful. */ function wp_a_new_and_stable_feature() { // ... } }类声明同样处理/** * WP_A_Stable_Class class * * package WordPress * since 6.3.0 */ if ( ! class_exists( WP_A_Stable_Class ) ) { // Do not invert this pattern with an early return. // See below for details... class WP_A_Stable_Class { ... } }真实仓库中有大量此类范例例如 lib/compat/wordpress-7.1/icons.php 用if ( ! function_exists( wp_register_icon_collection ) )包装图标注册 APIlib/compat/wordpress-7.1/class-wp-icon-collections-registry.php 与 class-wp-rest-icon-collections-controller.php 用if ( ! class_exists( ... ) )包装类blocks.php 中的_wp_apply_block_content_filters亦然。但对常青代码或任何预期在两个 WordPress 版本之间持续变动的插件代码而言class_exists()/function_exists()包装通常并不合适因为它会阻止最新版代码被使用。文档给出的典型反例是class_exists( WP_Theme_JSON )会返回true因为该类已存在于 Core 中——若对常青代码做此检查插件永远无法加载自己的新版本。return是反模式在class_exists()上下文中不要用提前return来反转判断。PHP 的return在包含文件中并不会终止脚本解析可能引发难以排查的副作用。以下写法是文档明确禁止的/** * ANTI-PATTERN * DO NOT COPY! * */ if ( class_exists( WP_A_Stable_Class ) ) { return; // do not do this. }何时用哪种前缀拿不准就用gutenberg前缀的选择是个权衡判断但一般规则是如果不确定就用gutenberg前缀因为它引发命名冲突的可能性更小。何时不使用插件专属前缀上述建议仅适用于 Gutenberg 插件lib目录中的文件。插件专属前缀不应出现在 Core PHP 代码中——将/lib文件同步到 Core 时Gutenberg前缀/后缀通常会手动替换为对应的WP_/wp_等价形式。同理除非是运行插件专属代码所必需否则在任何块blockPHP 代码中也应避免使用插件专属前缀插件中的 Core 块以 NPM 包形式发布见 packages/block-library 目录Core 以 NPM 依赖的方式消费它们。文档与注释规范为合并做准备对于插件中的每个类、方法和函数都应遵循WordPress PHP 内联文档标准编写注释。特别重要的是遵守注解规范尤其是since注解必须指明目标 WordPress 版本这样所有贡献者都能轻易识别某个功能已经/应当在何时合并进 Core。除此之外开发者还应在注释中简述该特性应如何合并进 Core——例如应补丁到哪个 Core 文件或函数。文档给出的范例/** * Returns a navigation object for the given slug. * * Should live in wp-includes/navigation.php when merged to Core. * * since 6.3.0 * * param string $slug * return WP_Navigation */ function wp_get_navigation( $slug ) { ... }这类合并说明能帮助未来的开发者知道在将 Gutenberg 特性合并进 Core 时具体该做什么。真实代码中也能看到类似实践如 lib/compat/plugin/fonts.php 的core-merge: Do not merge this function...注释。按功能feature组织 PHP 代码开发者应按功能feature而非按组件component组织 PHP 文件与文件夹。同时定义钩子函数后应立即调用add_action/add_filter完成挂载。这两条实践让 PHP 代码可以轻松地从一个文件夹如lib/experimental通过一次git mv迁移到另一个文件夹。推荐写法// lib/experimental/navigation.php function wp_get_navigation( $slug ) { ... } function wp_register_navigation_cpt() { ... } add_action( init, wp_register_navigation_cpt );不推荐写法// lib/experimental/functions.php function wp_get_navigation( $slug ) { ... } // lib/experimental/post-types.php function wp_register_navigation_cpt() { ... } // lib/experimental/init.php add_action( init, wp_register_navigation_cpt );对照真实仓库lib/init.php 正是这种模式的体现gutenberg_menu()函数定义后紧跟add_action( admin_menu, gutenberg_menu, 9 );函数与钩子挂载同处一个文件后续若要整体迁移只移动一个文件即可。在 lib/load.php 中组织文件引入lib/load.php是插件 PHP 代码的总入口。文档要求只要加载顺序允许就应按 WordPress 版本分组引入再按功能细分并参考lib/load.php中已有的注释。真实文件完全遵循这一约定版本分组先加载compat/wordpress-7.1lib/load.php再加载compat/wordpress-7.2lib/load.php后加载的版本理论上可以覆盖/补充先加载的版本功能分组实验特性集中在一段lib/load.php常青代码集中在一段lib/load.php块支持block supports覆盖集中在一段lib/load.php客户端媒体处理、交互 API、覆盖模式等各自成段。此外lib/load.php还展示了几个值得注意的实现细节文件以if ( ! defined( ABSPATH ) ) die( Silence is golden. );做直接访问防护并定义了IS_GUTENBERG_PLUGIN常量与向后兼容的GUTENBERG_VERSION常量lib/load.php。何时将 Gutenberg PHP 与 Core 双向同步Gutenberg 与 WordPress Core 之间是一个双向同步的生态新功能、缺陷修复及其他改动会在两个代码库之间往返。从 Gutenberg 到 Corebackport在打开的 Gutenberg PR 上对特定文件的改动会被标记为需要同步backport到 WordPress Core典型例子就是/lib下的 PHP 文件和 PHP 单元测试。CI 检查会明确提示你是否需要创建 Core PR如果需要你就必须在 backport-changelog 中按相应版本子目录创建一个 markdown 文件。仓库中的 backport-changelog/6.6、6.7、6.8、6.9、7.0、7.1、7.2 等目录即按 WordPress 大版本组织。创建 Core backport changelog 文件的具体流程详见 backport-changelog/readme.md先在 WordPress Core Trac 创建 ticket并向 WordPress Core 仓库提交 pull request文件名取 Core PR 的编号。例如 Core PR 号为1234、属于 WordPress 6.9 版本则创建backport-changelog/6.9/1234.md若目录不存在则创建文件内容为Core PR 的 URL后跟其 backport 的所有 Gutenberg PR 的 URL 列表一个 Core PR 可以包含一个或多个 Gutenberg PR 的改动如果1234.md已存在则把新增 Gutenberg PR 追加到既有列表中。格式示例一个 Core PR 合并两个 Gutenberg PRhttps://github.com/WordPress/wordpress-develop/pull/1234 * https://github.com/WordPress/gutenberg/pull/1111 * https://github.com/WordPress/gutenberg/pull/2222真实示例见 backport-changelog/6.7/6668.md文件以 Core PRwordpress-develop/pull/6668的 URL 开头下方列出被 backport 的 Gutenberg PR62092。使用独立文件而非单一 changelog 文件的原因是为了避免 rebase 冲突——并发 PR 各自新增独立文件互不干扰。例外情况与豁免标签部分 Gutenberg PR 会被错误标记为需要 Core backport PR例如仅包含注释微调、或改动已存在于 Core 的情况。此时可以使用两个 GitHub 标签豁免 CI 检查Backport from WordPress Core表示该 PR 本身就是从 WordPress Core backport 过来的无需再创建 Core PRNo Core Sync Required表示改动无需同步到 WordPress Core。如果某些文件或目录永远不应被标记为需要 Core backport PR还可以把它们加入工作流配置中的例外清单对应check-backport-changelog相关 CI 工作流。从 Core 到 Gutenberg反过来如果你在 WordPress Core 中改动了也存在于 Gutenberg 插件中的代码这些改动同样需要同步回 Gutenberg。相应的 Gutenberg GitHub PR 应打上Backport from WordPress Core标签。PHP 单元测试的同步与libPHP 文件同步对应的还有 PHP 单元测试。仓库中的 phpunit 目录如 phpunit/block-supports、phpunit/blocks、phpunit/experimental 等保存着与插件 PHP 代码对应的测试改动lib代码时通常需要同步更新这些测试并一同纳入 backport 范围。结语一套可长期维护的 PHP 贡献规范Gutenberg 插件的lib目录之所以采用experimental / compat/wordpress-X.Y / compat/plugin 根目录常青代码的结构本质上是为了支撑插件与 WordPress Core 之间高频、双向、可持续的代码同步。这套规范可以概括为几条核心原则按版本与功能组织目录拿不准就用gutenberg前缀稳定代码用function_exists()/class_exists()防重复声明但绝不用于常青代码函数定义与钩子挂载同文件同现注释写明since版本与合并去向改动/lib与 PHP 测试时按流程登记 Core backport changelog。遵循这些约定无论你的改动最终进入 Core 还是留在插件内都能被后续贡献者轻松识别、安全迁移。如果仍有疑问文档始终建议联系其他贡献者或到 WordPress Slack 的#core-editor频道求助。【免费下载链接】gutenbergThe Block Editor project for WordPress and beyond. Plugin is available from the official repository.项目地址: https://gitcode.com/GitHub_Trending/gu/gutenberg创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考