EP217. “用 block.json 迁移 Footer:register_block_type_from_metadata”
🔒 登录后可标记已读先复制一份 Block Theme 主题文件夹(fictional-block-theme → fictional-clean-blocks),保留旧版本作参照,在新副本里用官方标准做法重新实现最简单的 Footer Block。核心变化:所有 Block 相关文件统一放进 src/{block名}/ 子文件夹(@wordpress/scripts 会自动扫描 src/ 下每一个带 block.json 的子文件夹,不需要手动列举),每个 Block 文件夹里固定放 block.json(声明名字/标题/脚本/渲染文件路径)、render.php(PHP 渲染内容,取代上一章手写的渲染回调方法)、index.js(编辑器脚本,用 registerBlockType + 读取 block.json 的 metadata)。PHP 端注册也从手写一整套「注册脚本 + 注册 Block 类型」的样板代码,精简成一行 register_block_type_from_metadata()。
涉及文件
wp-content/themes/fictional-clean-blocks/(新建,复制自fictional-block-theme)wp-content/themes/fictional-clean-blocks/style.css(修改,改主题名)wp-content/themes/fictional-clean-blocks/functions.php(修改,注释掉旧的footer占位 Block,新增一行现代注册代码)wp-content/themes/fictional-clean-blocks/src/footer/block.json(新建)wp-content/themes/fictional-clean-blocks/src/footer/render.php(新建,从旧的our-blocks/footer.php搬运内容)wp-content/themes/fictional-clean-blocks/src/footer/index.js(新建)wp-content/themes/fictional-clean-blocks/package.json(修改,新增blocks脚本)
代码实现
src/footer/block.json(新建):
{
"$schema": "https://schemas.wp.org/trunk/block.json",
"apiVersion": 3,
"name": "ourblocktheme/footer",
"title": "Fictional University Footer",
"editorScript": "file:./index.js",
"render": "file:./render.php"
}
src/footer/render.php(新建,原样搬运旧的 our-blocks/footer.php 内容):
<footer class="site-footer">
<div class="site-footer__inner container container--narrow">
<div class="group">
<div class="site-footer__col-one">
<h1 class="school-logo-text school-logo-text--alt-color"><a href="<?php echo site_url() ?>"><strong>Fictional</strong> University</a></h1>
<p><a class="site-footer__link" href="#">555.555.5555</a></p>
</div>
<!-- ...其余页脚 HTML 结构不变... -->
</div>
</div>
</footer>
src/footer/index.js(新建):
import { registerBlockType } from "@wordpress/blocks"
import metadata from "./block.json"
function Edit() {
return <div>Hello, I am the footer block in the editor.</div>
}
registerBlockType(metadata.name, {
edit: Edit
})
functions.php:注释掉旧的占位 Block,新增一行 register_block_type_from_metadata():
// new PlaceholderBlock("footer");
// Register our new blocks
function our_new_blocks() {
register_block_type_from_metadata(__DIR__ . '/build/footer');
}
add_action('init', 'our_new_blocks');
package.json:新增 blocks 脚本(不指定入口文件,靠自动扫描):
"scripts": {
"start": "wp-scripts start src/index.js our-blocks/banner.js our-blocks/genericheading.js our-blocks/genericbutton.js our-blocks/slideshow our-blocks/slide",
"blocks": "wp-scripts start --experimental-modules",
"dev": "wp-scripts start",
"devFast": "wp-scripts start",
"test": "echo \"Error: no test specified\" && exit 1"
}
关键改动点:
- 先复制整个主题文件夹再动手改,保留旧版本对照:这一章的转换过程会逐个 Block 迁移,随时可能想回头参考旧写法是怎么实现同样功能的,留一份没有改动过的原版更安全
src/{block名}/是这套现代做法的核心目录约定:只要 Block 相关文件放在src/目录下、且这个子文件夹里有一份block.json,@wordpress/scripts就能自动识别、自动处理构建——不再需要像上一章那样,每新增一个 Block 就要去package.json手动追加一段入口路径block.json集中声明所有元信息:$schema:给 IDE/编辑器提供字段提示,不影响功能apiVersion: 3:写这门课时最新的 Block API 版本name:必须跟原本命名空间/Block 名保持一致(ourblocktheme/footer),这样前台/编辑器的行为才能跟旧版本一一对应editorScript: "file:./index.js":声明编辑器要加载的 JS 文件,用相对路径file:./前缀render: "file:./render.php":这是取代上一章render_callback方法的新写法——不用再手写一个 PHP 方法去ob_start()/require/ob_get_clean(),只需要在block.json里指定一个 PHP 文件路径,WordPress 会自动去渲染这个文件的输出作为 Block 的最终内容
- PHP 端注册精简成一行
register_block_type_from_metadata(__DIR__ . '/build/footer'):这个 WordPress 内建函数直接读取指定目录下的block.json,自动完成「注册脚本、注册样式、绑定渲染文件」这一整套原本要手写的样板代码——传入的路径指向编译产物所在的build/footer目录(不是src/footer),因为index.js要经过转译才能在浏览器里运行 index.js的写法:import metadata from "./block.json"直接把block.json当模块导入,取metadata.name当作registerBlockType()的第一个参数——这样 Block 名字只需要在block.json里维护一份,不需要在 JS 里重复写一遍容易脱节的字符串- 先写最简单的占位
Edit函数(<div>Hello, I am the footer block in the editor.</div>)验证整条链路能跑通,真正的编辑器 JSX 内容留到下一讲 - 新增独立的
blocks脚本,跟原本的start脚本并行运行、互不干扰:"blocks": "wp-scripts start --experimental-modules"——不传任何入口文件路径,让它用「自动扫描src/下所有带block.json的子文件夹」这个默认行为;写这门课时这个自动扫描能力还需要加--experimental-modules这个参数才能启用 - 旧的
start脚本暂时保持原样不变:因为还没迁移完的 Block(Banner、标题、按钮、幻灯片等)依然需要旧脚本继续处理,新旧两套构建任务分别在两个终端窗口同时运行——后面的讲座会讲怎么把两套任务合并成一条命令 - 验证方式:先看
build/footer/目录下是否真的生成了对应的编译产物(证明自动扫描生效),再看前台页脚是否正确显示(证明render.php生效),最后看编辑器里插入这个 Block 时是否显示占位文字而不是报错(证明index.js的registerBlockType生效)
Hook / Function 速查
| 名称 | 类型 | 用途 |
|---|---|---|
block.json 的 render 属性 | Block 元数据字段 | 声明一个 PHP 文件,WordPress 自动渲染它的输出作为 Block 内容,取代手写 render_callback |
register_block_type_from_metadata($目录路径) | WP 内建 function | 读取指定目录下的 block.json,一次性完成脚本/样式注册和渲染绑定 |
import metadata from "./block.json" | JS 模块导入 | 直接把 block.json 当模块使用,metadata.name 取代手写字符串 |
wp-scripts start --experimental-modules | 命令行参数 | 启用自动扫描 src/ 下所有 Block 子文件夹的能力(写这门课时仍是实验性功能) |
常见坑
register_block_type_from_metadata()传入的路径指向src/而不是编译产物所在的build/——JS 还没经过转译,注册的脚本文件不存在block.json里的name跟旧版本对不上——前台渲染出的 HTML 结构没变,但 Block 类型名字变了,会被 Gutenberg 当成完全不同的 Block,导致已有内容里的旧引用失效- 忘记新旧两套构建任务(
start和blocks)要同时运行——只跑其中一个,另一批还没迁移完的 Block 会因为缺少编译产物而报错
延伸 / 后续讲座会用到
下一讲继续完善 Footer Block 的编辑器 JSX 内容,并把这套「多入口构建脚本要分开跑」的问题一并解决。
Sources
Udemy:
- Become a WordPress Developer: Unlocking Power With Code — Section 29, EP217