EP05. "wp-headless-and-wpgraphql Headless 与 WPGraphQL 审查"
🔒 登录后可标记已读- Headless WordPress 最容易出事的地方不是 CMS 后台,是那道「前端到底能不能看见草稿」的边界——一个 preview 端点只认 slug 不验证 token,就等于把未发布内容公开给任何人猜
- 这是
jorgerosal/wordpress-skills里专盯「WordPress 当 CMS、前端另起炉灶(Next.js/Gatsby/Remix)」这种解耦架构的技能,看的是 WPGraphQL schema 设计、resolver 性能、preview/auth 流程、缓存失效策略 - 核心原则:schema 要反映耐用的内容边界和可预期的前端需求,同时 auth、preview、缓存、构建流程必须对「信任边界」和「失效规则」保持明确,不能靠前端隐藏来充当权限控制
- 前置知识:先看过 Overview 系列「Claude Code 是什么与新手上手」「进阶功能:Skills、Plugins 与 Routines」,以及 EP01「wp-security-review 安全审查」了解这套 skill 包怎么调用
重点内容
这个 Skill 是做什么的
系统审查通过 WPGraphQL 或类似 API 暴露内容的 headless WordPress 项目:schema 边界设计、resolver 性能、preview/auth 正确性、缓存失效规则、内容建模决策。
适合用在:
- Review 用 WPGraphQL 驱动的主题、插件或 headless 集成
- 审查自定义 schema 扩展和 resolver 代码
- Review 前端拉取 WordPress 内容的数据获取模式
- 规划 preview、draft、auth、或 revalidation 流程
- 检查构建流程、webhook 失效逻辑、或 persisted query 配置
不适合用在:
- 没有 GraphQL 层的纯 REST 集成(交给
wp-rest-api-development) - 没有 headless 前端顾虑的 ACF 字段组设计(交给
wp-acf-and-content-modeling) - 没有解耦前端的通用插件架构审查(交给
wp-plugin-development) - 纯 Playground demo 搭建(交给
wp-playground-development)
触发方式
| 方式 | 写法 | 说明 |
|---|---|---|
| 斜线指令(完整版) | /wp-headless-review [path] | 完整审查,附严重度分级和修法建议 |
| 斜线指令(快速版) | /wp-headless [path] | 只抓关键 schema/preview/auth 问题,适合日常小改动后快速过一遍 |
| 自然语言 | 「审查这个 WPGraphQL schema」「check this headless preview flow」 | Claude 判断意图符合就自动触发 |
审查覆盖的四个层面
| 层面 | 关注点 |
|---|---|
| WPGraphQL Schema 扩展 | schema 有没有在没做权限检查的情况下暴露私有/meta 数据;resolver 是不是每个节点重复跑 get_post_meta()/WP_Query 而没有批量处理或缓存;字段命名/返回类型跟领域模型对不上,逼前端绕路处理 |
| 前端查询层 | route/page 查询拉了一整棵大树但只渲染几个字段;同一个内容类型在不同模板/路由里重复维护 fragment;preview 模式和生产模式共用同一份缓存 |
| Preview 与 Auth 流程 | preview 端点只信任 slug 或 post ID、不验证 capability/token 归属;草稿/私有内容变得在 CDN 或应用层可被缓存;没有区分编辑者的 preview 流量和公开流量 |
| 构建 / Revalidation / Webhook | 每次内容改动都触发全量重建、没有范围控制;webhook 没有标明是哪些路由/内容依赖这次改动;revalidation 失败没有重试/校验路径 |
判定 CRITICAL / WARNING / INFO 的标准
- CRITICAL:未发布内容被暴露、preview/auth 流程不安全、resolver 没有边界导致数据泄漏或生产不稳定
- WARNING:脆弱的 schema 建模、resolver 开销大、缺分页、缓存失效规则薄弱、前端跟不稳定的字段形状绑得太死
- INFO:命名、fragment、schema 文档、persisted-query 规范、构建可观测性可以做得更好
实操示例
// ❌ WARNING:把原始存储 key 直接暴露成 GraphQL 字段("meta-as-API"),
// 前端跟存储细节绑死,字段还容易一个一个越加越多,管理不起来
register_graphql_field( 'Post', 'heroImageUrl', [
'type' => 'String',
'resolve' => static function( $post ) {
return get_post_meta( $post->ID, 'hero_image_url', true );
},
] );
// ✅ GOOD:字段名按领域概念命名,复用已有的 media 关系,而不是照搬存储 key
// (具体实现视项目而定,关键是不要让 schema 字段名等于数据库 meta key)
// ❌ CRITICAL:无边界的 GraphQL connection,前端一改查询参数就能把全部文章拉下来,
// 容易被无意间当成 DOS,缓存也没法做得确定
register_graphql_connection( [
'fromType' => 'RootQuery',
'toType' => 'Article',
'fromFieldName' => 'allArticles',
'resolve' => static function() {
return new WP_Query( [
'post_type' => 'article',
'posts_per_page' => -1,
] );
},
] );
// ✅ GOOD:强制分页 + 明确的筛选/排序参数,widen 之前先看清楚前端实际怎么消费这个 connection
// ❌ CRITICAL:preview 端点只认 slug,没有 token 校验、没有绑定具体的修订版本/编辑者会话,
// 谁都能猜 URL 探测未发布内容
export async function GET(req: Request) {
const slug = new URL(req.url).searchParams.get('slug');
return Response.redirect(`/posts/${slug}`);
}
// ✅ GOOD 方向:要求签名 secret,服务端解析出规范的内容 ID,
// 校验通过之后才进入 preview 模式
怎么安装
这个 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-headless-and-wpgraphql ~/.claude/skills/ | 只想要 headless/WPGraphQL 审查这一个功能,不要其他 17 个 |
装完重启 Claude Code,进到一个 WordPress 项目里跑 /wordpress-skills:wp-headless-review 验证有没有装成功(用 marketplace/submodule 方式装的话,指令前面会带插件命名空间 wordpress-skills:;用「只装这一个 skill」的方式则不带命名空间,直接 /wp-headless-review)。
Claude Desktop / claude.ai: 走 Settings → Capabilities → Skills,上传技能文件夹(把 claude-skills/wp-headless-and-wpgraphql 这个文件夹打包上传,里面要包含 SKILL.md)——跟 Claude Code 的 git submodule/marketplace 安装方式不同,Desktop 端是手动上传 UI,装好之后同样能用自然语言或 slash 指令触发。
常见错误
- ❌ 前端代码里
client.request(PreviewQuery, { id })这类调用被认为「肯定没问题」——问题在于前端可能借着公开 API 路径请求 preview-only 字段,权限变得隐式、难以推理,应该用独立的 preview client 配置和显式凭证 - ❌ 把「每次内容改动都重建」直接当成 CRITICAL——这类问题通常是 WARNING(没有范围控制的构建触发),除非确实导致草稿内容被生产环境缓存住才升级成 CRITICAL
- ❌ 忽略 webhook 没有标明依赖哪些路由/内容——这看起来只是流程问题,实际会导致「改了一个字段却不知道该刷新哪些页面」的排查噩梦
- ❌ 只审查 PHP resolver,不看前端的
getStaticProps/getServerSideProps/generateStaticParams里怎么用 preview/draftMode/revalidate——headless 的问题一半藏在前端代码里 - 💡 找不到问题时也不能只说「没问题」——要顺手提醒还有哪些残留风险,比如 preview 文档不全、缺失效可观测性、或者随着前端演进 schema 容易漂移的区域
Sources
官方文档:
- wordpress-skills(GitHub 仓库)— https://github.com/jorgerosal/wordpress-skills
- wp-headless-and-wpgraphql SKILL.md — https://github.com/jorgerosal/wordpress-skills/blob/main/claude-skills/wp-headless-and-wpgraphql/SKILL.md