AI TOOLS

EP06. "wp-block-development Block 开发审查"

首页 AI 工具 Claude · Skills · WordPress Skills · EP06
约 20 分钟· #EP06#Claude#WordPress Skills
🔒 登录后可标记已读
  • Dynamic block 里塞了 InnerBlocks,结果 save 函数返回 null——内容一发布,用户辛辛苦苦排好的嵌套 block 直接从数据库消失,这是最容易被忽略又最伤的一种坑
  • wp-block-developmentjorgerosal/wordpress-skills 里专盯 Gutenberg block 开发的技能,同时审 PHP(register_block_type()、render callback)和 React/JSX(edit/save 函数)两边的代码
  • 核心原则:block 是「编辑器用 React 组件、前台用静态 HTML 或 PHP 服务端渲染」的双轨架构,block.json 是唯一真相来源(single source of truth)
  • 前置知识:先看过 Overview 系列「Claude Code 是什么与新手上手」「进阶功能:Skills、Plugins 与 Routines」,以及 EP01「wp-security-review 安全审查」了解这套 skill 包怎么调用

重点内容


这个 Skill 是做什么的

系统审查 WordPress 6.x+ block editor(Gutenberg)代码:block.json schema 校验、editor 组件模式(edit/save 函数)、服务端渲染(render callback / render 文件)、属性(attributes)处理、block 版本迁移(deprecation)管理、Interactivity API 用法。审查同时覆盖 PHP(遵循 WordPress PHP Coding Standards:括号内加空格、用 array() 不用 []、Yoda 条件)和 JS/JSX(遵循 WordPress JS 规范:tab 缩进、JSDoc 注释、变量用 camelCase、组件用 PascalCase)。

适合用在:

  • Block 插件代码审查(单个 block、多 block、或 block 库)
  • block.json schema 校验与字段核实
  • Editor 组件审查(edit/save 函数、React/JSX 模式)
  • Render callback 或 render 文件审计(服务端 PHP)
  • InnerBlocks 模式审查(嵌套 block、template、templateLock)
  • Block deprecation 检查(save 函数迁移)
  • Interactivity API 指令审查(WP 6.5+ 前端交互)
  • useBlockPropsRichTextInspectorControlsBlockControls 用法

不适合用在:

  • theme.json 配置(交给 wp-theme-development
  • 跟 block editor 无关的通用 React 应用审查
  • WooCommerce block 扩展
  • 纯安全审查(交给 wp-security-review
  • 纯插件架构审查(交给 wp-plugin-development
  • 纯性能审查(交给 wp-performance-review

触发方式

方式写法说明
斜线指令(完整版)/wp-block-review [path]完整审查,PHP 和 JS/JSX 按实际路径混排分组
斜线指令(快速版)/wp-block [path]只抓关键 block 问题,适合日常小改动后快速过一遍
自然语言「审查这个 block 的 edit/save 函数」「check this block.json schema」Claude 判断意图符合就自动触发

📌 只审 src/ 里的源码(反映开发者真实意图),build/ 目录是编译产物,不审代码质量,只检查是不是缺失或过期(对比 index.asset.php 时间戳跟 src/ 修改时间)。


按检查对象分类的重点

检查对象CRITICAL 举例WARNING 举例
block.jsonapiVersion(block 注册失败);name 格式不对(不是 namespace/block-nameapiVersion 还停在 1 或 2(应升到 3,享受 WP 6.3+ 的 iframe 隔离)
Edit 函数没调用 useBlockProps();用 window.wp.* 而不是 @wordpress/* 引入(老写法,破坏现代构建流程)
Save 函数 / 静态 blockapiVersion 3 下 save 没调用 useBlockProps.save()(会造成 block validation 报错)save 函数里用 Math.random()/Date.now()(save 必须是确定性的,同样的属性要输出同样的 markup)
Dynamic block用了 InnerBlocks 但 save 返回 null(嵌套内容直接丢失)
Render callback / render.php对 InnerBlocks 的 $content 参数用 wp_kses_post()(会破坏 embed)没用 get_block_wrapper_attributes(),手动拼 class(丢失 block supports)
Attributestypesource 组合不合法;用 source: 'meta'(已弃用,改用 useEntityProptype 跟实际数据类型对不上

实操示例:Static Block(静态区块)

// ❌ BAD:edit 和 save 都没调用 useBlockProps
// edit.js
export default function Edit( { attributes, setAttributes } ) {
	return (
		<div className="my-block">
			<input
				value={ attributes.content }
				onChange={ ( e ) => setAttributes( { content: e.target.value } ) }
			/>
		</div>
	);
}

// save.js
export default function save( { attributes } ) {
	return (
		<div className="my-block">
			<p>{ attributes.content }</p>
		</div>
	);
}
// ✅ GOOD:完整的静态 block,正确用 useBlockProps 和 RichText
// edit.js
import { useBlockProps, RichText } from '@wordpress/block-editor';

export default function Edit( { attributes, setAttributes } ) {
	const blockProps = useBlockProps();
	return (
		<div { ...blockProps }>
			<RichText
				tagName="p"
				value={ attributes.content }
				onChange={ ( content ) => setAttributes( { content } ) }
				placeholder="Enter content..."
			/>
		</div>
	);
}

// save.js
import { useBlockProps, RichText } from '@wordpress/block-editor';

export default function save( { attributes } ) {
	const blockProps = useBlockProps.save();
	return (
		<div { ...blockProps }>
			<RichText.Content tagName="p" value={ attributes.content } />
		</div>
	);
}

实操示例:Dynamic Block + InnerBlocks(最容易踩的坑)

// ❌ CRITICAL:dynamic block 用了 InnerBlocks,但 save 返回 null
// —— 用户排好的嵌套 block 内容会直接消失
// edit.js
import { useBlockProps, InnerBlocks } from '@wordpress/block-editor';

export default function Edit() {
	const blockProps = useBlockProps();
	return (
		<div { ...blockProps }>
			<InnerBlocks />
		</div>
	);
}

// save.js —— 嵌套内容会丢失!
export default function save() {
	return null;
}
// ✅ GOOD:即使是 dynamic block,只要用了 InnerBlocks,
// save 也必须返回 <InnerBlocks.Content />,前台渲染再靠 render.php 的 $content 参数接住
// save.js
import { InnerBlocks } from '@wordpress/block-editor';

export default function save() {
	return <InnerBlocks.Content />;
}
<?php
// render.php —— 用 $content 参数拿到 InnerBlocks 生成的 HTML
defined( 'ABSPATH' ) || exit;

$wrapper_attributes = get_block_wrapper_attributes();
?>
<div <?php echo $wrapper_attributes; ?>>
	<h3><?php echo esc_html( $attributes['title'] ); ?></h3>
	<?php echo $content; // InnerBlocks HTML —— 千万不要对它用 wp_kses_post(),会破坏 embed ?>
</div>

怎么安装

这个 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-block-development ~/.claude/skills/只想要 block 开发审查这一个功能,不要其他 17 个

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

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

常见错误

  • ❌ Dynamic block 的 save 函数返回 null 就被当成 bug——这本来就是对的,服务端 PHP 负责渲染输出,save 不需要返回 markup(只有「用了 InnerBlocks 却返回 null」才是真的 CRITICAL)
  • ❌ Block 没有 viewScript 就被要求补上——block 没有前端交互行为的话(纯编辑器展示或静态 HTML),本来就不需要 viewScript
  • apiVersion 还是 2 就直接判 CRITICAL——2 在 WordPress 6.x+ 里照样能跑,只是少了 iframe 隔离,建议升级但不是必须
  • ❌ Block 没有 supports 字段就扣分——简单 block 本来就不一定需要 color/spacing/typography 这些自定义能力,这是刻意的极简设计
  • ❌ 浏览器 console 里出现 window.wp.* 就当成源码问题——console 调试时用没关系,只有源码(.js 文件)里的 import 用 window.wp.* 才是该抓的反模式
  • ❌ 只加了新的可选属性(optional attribute)就要求写 deprecated 数组——只有 save 函数产出的 markup 变了才需要写 deprecation,新增可选属性不会破坏已有内容
  • 💡 发现未转义输出或 Interactivity API 里塞了用户输入,报告里提醒一句「安全问题,建议跑 /wp-sec-review」;发现 init 钩子注册、ABSPATH 检查缺失这类插件架构问题,提醒跑 /wp-plugin-review——这个 skill 本身不深挖这两块

Sources

官方文档:

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