AI TOOLS

EP03. "wp-plugin-development 插件架构审查"

首页 AI 工具 Claude · Skills · WordPress Skills · EP03
约 19 分钟· #EP03#Claude#WordPress Skills
🔒 登录后可标记已读
  • 插件头信息漏写 Text Domain、函数名没加前缀、CPT 注册在 init 里每次都 flush_rewrite_rules()——这些坑要么让 WordPress.org 直接拒审,要么在别人服务器上跟其他插件打架,wp-plugin-development 就是揪这些
  • wp-security-review 关注漏洞、wp-performance-review 关注速度不同,这个 skill 专盯插件本身的架构:生命周期钩子、CPT/taxonomy 注册、Settings API、hooks 设计、国际化、WordPress.org 上架合规
  • 六步流程:先判断插件类型和场景(WordPress.org 提交 / 私有插件 / mu-plugin / drop-in,各自标准不同),再依序抓 CRITICAL → WARNING → INFO
  • 前置知识:先看过 Overview 系列「Claude Code 是什么与新手上手」「进阶功能:Skills、Plugins 与 Routines」,以及 EP01「wp-security-review 安全审查」了解这套 skill 包的调用方式

重点内容


这个 Skill 是做什么的

系统审查 WordPress 插件架构是否符合规范:插件头信息完整度、ABSPATH 检查、函数/类前缀、激活/停用/卸载生命周期、CPT 与 taxonomy 注册、Settings API 完整流程、hooks 系统(action/filter 的 priority、返回值、移除)、国际化(i18n/l10n)、WordPress.org 提交合规(Plugin Check)。跟安全相关的具体做法(nonce、sanitize)它只是提醒一句,深挖交给 wp-security-review

适合用在:

  • 插件代码架构审查
  • WordPress.org 插件目录提交前检查
  • 审查激活/停用/卸载生命周期钩子
  • 审查自定义 post type 或 taxonomy 注册
  • 校验 Settings API 实现
  • 检查 hooks 系统用法(action/filter 的 priority、移除)
  • 国际化(i18n/l10n)审计
  • WordPress Plugin Check(PCP)合规验证
  • 前缀/命名空间冲突检测

不适合用在:

  • 主题开发(交给 wp-theme-development
  • Gutenberg block 开发(交给 wp-block-development
  • WooCommerce 扩展开发
  • 纯安全审查(交给 wp-security-review
  • 纯性能审查(交给 wp-performance-review

触发方式

方式写法说明
斜线指令(完整版)/wp-plugin-review [path]完整审查,按文件分组输出,附 BAD/GOOD 代码对照
斜线指令(快速版)/wp-plugin [path]只抓关键架构问题,适合日常小改动后快速过一遍
自然语言「审查这个插件的架构」「check this plugin for WordPress.org submission」Claude 判断意图符合就自动触发

场景决定标准松紧

同一个反模式,在不同发行场景下的严重度不一样:

场景判断标准
WordPress.org 提交最严格,Plugin Check 工具会强制这些要求:Text Domain 必须跟插件 slug 完全一致(小写、连字符不能用底线)、所有 PHP 文件都要有 ABSPATH 检查、所有 i18n 函数必须带 text domain 参数、不能用已弃用函数、必须 GPLv2+ 授权、要有 readme.txt
私有 / 企业内部插件更灵活,不强制 readme.txt,可以用私有授权协议,命名可以不那么严格(但前缀还是要有,避免跟其他插件冲突)
Must-use 插件(mu-plugin)自动加载、不能通过后台停用,没有激活/停用钩子(因为它们不走激活/停用流程),这不是缺陷
Drop-in 插件(如 object-cache.phpdb.php用特定文件名替换 WordPress 核心功能,不用标准插件头信息,不用激活钩子,审查重点是跟核心预期行为的兼容性

实操示例

// ❌ CRITICAL:没有前缀,跟其他插件命名冲突风险高
function save_settings() {
    update_option( 'plugin_settings', $_POST['data'] );
}
class Plugin_Settings { /* ... */ }
add_action( 'admin_init', 'save_settings' );

// ✅ GOOD:函数/类都加前缀
function mypl_save_settings() {
    update_option( 'mypl_settings', $_POST['data'] );
}
class MyPL_Settings { /* ... */ }
add_action( 'admin_init', 'mypl_save_settings' );

// ✅ BETTER:直接用 PHP namespace(选项名还是要前缀)
namespace MyPlugin\Admin;
function save_settings() {
    update_option( 'mypl_settings', $_POST['data'] );
}
add_action( 'admin_init', __NAMESPACE__ . '\save_settings' );
// ❌ CRITICAL:CPT 注册在 init 钩子里,flush_rewrite_rules() 每次页面加载都跑一遍
add_action( 'init', 'mypl_register_cpt' );
function mypl_register_cpt() {
    register_post_type( 'book', array( 'public' => true ) ); // 没前缀,没 show_in_rest
    flush_rewrite_rules(); // 每个请求都会跑,非常昂贵
}

// ✅ GOOD:CPT 注册照常挂 init,flush_rewrite_rules() 只在激活钩子跑一次
add_action( 'init', 'mypl_register_cpt_and_taxonomy' );
function mypl_register_cpt_and_taxonomy() {
    register_post_type( 'mypl_book', array(
        'public'       => true,
        'has_archive'  => true,
        'show_in_rest' => true, // Gutenberg 支持
    ) );
}

register_activation_hook( __FILE__, 'mypl_activate' );
function mypl_activate() {
    mypl_register_cpt_and_taxonomy(); // 先注册
    flush_rewrite_rules(); // 只在激活时跑一次
}

register_deactivation_hook( __FILE__, 'mypl_deactivate' );
function mypl_deactivate() {
    flush_rewrite_rules();
}
// ❌ CRITICAL:filter 回调没有 return,直接破坏整条 filter 链、导致致命错误
add_filter( 'the_content', 'mypl_modify_content' );
function mypl_modify_content( $content ) {
    if ( is_single() ) {
        $content .= '<p>Footer text</p>';
    }
    // 漏了 return!
}

// ✅ GOOD:filter 回调永远要 return
add_filter( 'the_content', 'mypl_modify_content', 10, 1 );
function mypl_modify_content( $content ) {
    if ( is_single() ) {
        $content .= '<p>Footer text</p>';
    }
    return $content; // 永远要 return
}
// ❌ CRITICAL:变量直接内插进可翻译字符串,破坏翻译提取
$count = 5;
echo __( "You have $count messages", 'my-plugin' );
echo __( 'Save Settings' ); // 漏了 text domain
echo __( 'Save', 'my_plugin' ); // 底线而不是连字符,跟插件 slug 不一致

// ✅ GOOD:用 sprintf 传占位符,text domain 跟插件 slug 完全对齐
$count = 5;
echo sprintf(
    __( 'You have %d messages', 'my-awesome-plugin' ),
    $count
);
echo sprintf(
    _n( 'One post found', '%d posts found', $count, 'my-awesome-plugin' ),
    number_format_i18n( $count )
);

怎么安装

这个 skill 是 wordpress-skills 这个开源仓库(jorgerosal/wordpress-skills)打包的 18 个技能之一,安装一次,18 个技能一起到位,不用逐个装:

Claude Code:

方式指令适用场景
装进单个项目(推荐)git submodule add https://github.com/jorgerosal/wordpress-skills.git .claude/plugins/wordpress-skills只想在这个项目用,团队成员 clone 项目就一起有
装到自己账号git clone https://github.com/jorgerosal/wordpress-skills.git ~/.claude/plugins/wordpress-skills所有项目都能用
只装这一个 skillcp -r claude-skills/wp-plugin-development ~/.claude/skills/只想要插件架构审查这一个功能,不要其他 17 个

装完重启 Claude Code,进到一个 WordPress 项目里跑 /wordpress-skills:wp-plugin-review 验证有没有装成功(用 marketplace/submodule 方式装的话,指令前面会带插件命名空间 wordpress-skills:;用「只装这一个 skill」的方式则不带命名空间,直接 /wp-plugin-review)。

Claude Desktop / claude.ai: 走 Settings → Capabilities → Skills,上传技能文件夹(把 claude-skills/wp-plugin-development 这个文件夹打包上传,里面要包含 SKILL.md)——跟 Claude Code 的 git submodule/marketplace 安装方式不同,Desktop 端是手动上传 UI,装好之后同样能用自然语言或 slash 指令触发。

常见错误

  • ❌ mu-plugin 没有激活/停用钩子就被当成缺陷打回去——must-use 插件本来就自动加载,不走激活/停用流程,这是正常的
  • ❌ drop-in 插件(object-cache.php 等)没有标准插件头信息也被扣分——drop-in 用特定文件名替换核心功能,不需要标准头信息
  • ❌ 私有/企业插件没有 readme.txt 也被要求补——readme.txt 只有 WordPress.org 提交才强制要求
  • ❌ REST API 的 GET 端点用 __return_true 被当成漏洞——公开只读端点故意开放是正确写法,只有写操作用 __return_true 才该报警
  • ❌ Settings API 的 sanitize_callback 把 checkbox 字符串转成布尔值、文字转数组,被当成 bug——这是合法的类型转换
  • uninstall.php 里直接用 $wpdb->query() 执行 DROP TABLE 被要求改成 dbDelta()——dbDelta() 是给 CREATE/ALTER 用的,DROP 用原生 $wpdb->query() 才是对的写法
  • 💡 判断严重度前先确认插件的分发场景(WordPress.org / 私有 / mu-plugin / drop-in),同一个模式在不同场景下标准完全不同

Sources

官方文档:

  1. wordpress-skills(GitHub 仓库)— https://github.com/jorgerosal/wordpress-skills
  2. wp-plugin-development SKILL.md — https://github.com/jorgerosal/wordpress-skills/blob/main/claude-skills/wp-plugin-development/SKILL.md