EP10. "wp-admin-ui-development 后台界面审查"
🔒 登录后可标记已读- 插件的设置页是不是长得越来越像一个独立 app,而不是 WordPress 后台该有的样子?
wp-admin-ui-development就是专门抓这种「脱离后台惯例」的问题 wp-admin-ui-development是jorgerosal/wordpress-skills这套 18 个 skill 里专门审查 WordPress 后台界面的一个,覆盖菜单注册、Settings API 用法、通知、脚本加载、页面结构这几块- 核心原则一句话:后台界面要 capability-aware(权限敏感)、行为可预期、贴合 WordPress 后台惯例,不要做成自成一套的 app 式交互
- 前置知识:先看过 EP01「wp-security-review 安全审查」——这个 skill 也会碰到 nonce/capability 检查,但焦点是后台 UX 结构,不是全面安全审计
重点内容
这个 Skill 是做什么的
wp-admin-ui-development 审查设置页、插件 dashboard、add_menu_page()/add_submenu_page() 用法、后台表单、通知、脚本加载范围、list table 模式,判断整个后台界面结构是不是稳定、可维护、符合权限模型。
适合用在:
- 审查设置页或插件 dashboard
- 审计
add_menu_page()/add_submenu_page()用法 - 检查后台表单、通知、数据录入页面
- 审查后台脚本加载与页面定位(screen targeting)
- 分析后台页面的 capability 检查
不适合用在:
- 前端界面审查
- 纯安全审计(交给
wp-security-review) - 没有后台界面焦点的通用插件架构(交给
wp-plugin-development)
触发方式
| 方式 | 写法 | 说明 |
|---|---|---|
| 斜线指令(完整版) | /wp-admin-review [path] | 完整审查,结果按文件、按严重度分组 |
| 斜线指令(快速版) | /wp-admin [path] | 只抓高风险问题,速度快 |
| 自然语言 | 「审查这个设置页面」「check my admin menu registration」 | Claude 判断意图符合就自动触发 |
审查流程
- 识别后台界面类型:设置页、dashboard widget 或工具页、自定义 list table、modal 密集的后台流程
- 审查页面注册:menu slug、parent slug、capability、专用回调、页面专属的 enqueue 逻辑
- 审查表单与状态流转:有没有用 Settings API(或有意识地选择替代方案)、nonce 与 capability 检查、成功/失败提示是不是稳定
- 审查 UX 与可维护性:避免单页塞进过多表单内容、贴合 WordPress 后台布局惯例、脚本只在相关页面加载
- 按严重度分类:CRITICAL 是缺 capability 检查、任何角色都能碰到不该碰的后台操作;WARNING 是全局加载脚本、绕开 Settings API、通知 UX 不稳定、单页塞太多内容;INFO 是可以用核心组件或拆分页面结构
按检查对象分类的坑
| 检查对象 | CRITICAL | WARNING | INFO |
|---|---|---|---|
| 后台菜单注册 | 缺 capability 要求 | 菜单回调把路由、渲染、表单处理全部混在一起 | 大页面可以拆成独立 class/module |
| 设置表单 | 保存时缺 nonce 或 capability 检查 | 到处手写 update_option(),没有 Settings API 结构;设置项缺 sanitize callback | 设置可以拆成 section/tab 便于维护 |
| 后台脚本样式 | — | 脚本在每个后台页面都加载;大功能用 inline JS | 可以用 screen ID + 条件式 enqueue |
| 通知与反馈 | — | 持久通知没做关闭处理;成功/失败状态跟实际操作结果脱钩 | 可以做更清楚的空状态/加载状态 |
快速扫描指令(rg)
# CRITICAL:后台页面注册、admin-post 处理与 nonce/capability 检查
rg -n "add_menu_page|add_submenu_page|add_options_page|add_management_page" . -g '*.php'
rg -n "admin_post_|check_admin_referer|wp_verify_nonce|current_user_can" . -g '*.php'
# WARNING:全局 enqueue、直接改 option、后台通知
rg -n "admin_enqueue_scripts|wp_enqueue_script|wp_enqueue_style" . -g '*.php'
rg -n "update_option|add_option" . -g '*.php'
rg -n "admin_notices|notice-|is-dismissible" . -g '*.php'
# INFO:有没有用 Settings API、有没有做 screen 定位
rg -n "register_setting|add_settings_section|add_settings_field" . -g '*.php'
rg -n "get_current_screen|current_screen|\$hook_suffix" . -g '*.php'
实操示例
// ❌ CRITICAL:菜单注册没有 capability 要求,任何登录用户都能进
add_menu_page( '我的设置', '我的设置', '', 'myplugin-settings', 'myplugin_render_page' );
// ✅ GOOD:明确要求 capability
add_menu_page( '我的设置', '我的设置', 'manage_options', 'myplugin-settings', 'myplugin_render_page' );
// ❌ WARNING:脚本在每个后台页面都加载,不管当前是哪个页面
add_action( 'admin_enqueue_scripts', function () {
wp_enqueue_script( 'myplugin-admin', plugins_url( 'admin.js', __FILE__ ) );
} );
// ✅ GOOD:用 $hook_suffix 只在自己的设置页加载
add_action( 'admin_enqueue_scripts', function ( $hook_suffix ) {
if ( 'toplevel_page_myplugin-settings' !== $hook_suffix ) {
return;
}
wp_enqueue_script( 'myplugin-admin', plugins_url( 'admin.js', __FILE__ ) );
} );
// ❌ CRITICAL:保存动作没有 nonce、没有 capability 检查
add_action( 'admin_post_myplugin_save', function () {
update_option( 'myplugin_option', $_POST['value'] );
wp_safe_redirect( admin_url( 'admin.php?page=myplugin-settings' ) );
} );
// ✅ GOOD:走 Settings API,保存/校验/提示都由核心处理,不用手写 nonce 检查
add_action( 'admin_init', function () {
register_setting( 'myplugin_group', 'myplugin_option', array(
'sanitize_callback' => 'sanitize_text_field',
) );
add_settings_section( 'myplugin_main', '主设置', '__return_false', 'myplugin-settings' );
add_settings_field( 'myplugin_option', '选项值', 'myplugin_render_field', 'myplugin-settings', 'myplugin_main' );
} );
怎么安装
这个 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 | 所有项目都能用 |
| 只装这一个 skill | cp -r claude-skills/wp-admin-ui-development ~/.claude/skills/ | 只想要后台界面审查这一个功能,不要其他 17 个 |
装完重启 Claude Code,进到一个 WordPress 项目里跑 /wordpress-skills:wp-admin-review 验证有没有装成功(用 marketplace/submodule 方式装的话,指令前面会带插件命名空间 wordpress-skills:;用「只装这一个 skill」的方式则不带命名空间,直接 /wp-admin-review)。
Claude Desktop / claude.ai: 走 Settings → Capabilities → Skills,上传技能文件夹(把 claude-skills/wp-admin-ui-development 这个文件夹打包上传,里面要包含 SKILL.md)——跟 Claude Code 的 git submodule/marketplace 安装方式不同,Desktop 端是手动上传 UI,装好之后同样能用自然语言或 slash 指令触发。
常见错误
- ❌ 把「菜单回调里顺便处理了表单保存」一律当成 CRITICAL 打回——这个 skill 把「渲染/路由/表单处理混在一个回调里」列为 WARNING(可维护性问题),不是安全问题,别跟缺 capability 检查混为一谈
- ❌ 后台脚本没有做 screen 判断就要求必须重构——这是 WARNING/INFO 级的性能与可维护性建议,不是必须立刻修的阻断项
- ❌ 手写
update_option()而不是走 Settings API,被直接判定为漏洞——这属于 WARNING(结构/可维护性问题),只要保存动作本身有 nonce 和 capability 检查,不算安全漏洞 - ❌ 通知没做关闭处理(
is-dismissible)被当成必须项——这是 UX 层面的 WARNING 建议,不影响功能正确性 - 💡 判断严重度时先分清楚这是「安全」问题还是「架构/UX」问题:缺 capability 检查、任意角色能碰到后台操作,才是 CRITICAL;表单该不该用 Settings API、脚本该不该分页加载,是 WARNING/INFO
Sources
官方文档:
- wordpress-skills(GitHub 仓库)— https://github.com/jorgerosal/wordpress-skills
- wp-admin-ui-development SKILL.md — https://github.com/jorgerosal/wordpress-skills/blob/main/claude-skills/wp-admin-ui-development/SKILL.md