搜索全站
主题 10 分钟阅读

区块主题(FSE)怎么做子主题?theme.json 合并规则与父主题兼容

给 Twenty Twenty-Four 这类块主题做子主题,照搬传统方法会失效。本文讲清块主题目录结构、theme.json 父子合并逻辑与站点编辑器改动的优先级,附可复用配置。

U
UFO_PF 2025-02-10 · 阅读 10 分钟
区块 主题
阅读提示
本文约 3,941 字,预计阅读 10 分钟。文中命令与配置均经过实测,可直接参考执行。

引言:打开父主题,发现根本没有 header.php

传统主题做子主题的第一反应是:复制 header.php、footer.php 过来改。但当你打开一个区块主题(如 Twenty Twenty-Four、Twenty Twenty-Five)时,会发现里面没有这些 PHP 模板文件,只有 templates/index.html、parts/header.html 这类 HTML 文件,style.css 里也只有一段头注释,几乎没有实际样式。

于是问题来了:块主题的子主题到底靠什么工作?样式写在 theme.json 还是 style.css?为什么我在子主题里改了 parts/header.html,前台纹丝不动?这三个问题是区块主题(FSE)二次开发最常见的卡点,本质是对”文件—数据库—全局样式”三层来源的优先级不清楚。

原理分析:三层来源与优先级

块主题的模板渲染由核心的 get_block_template() / locate_block_template() 负责(位于 wp-includes/block-template.php)。模板有两个来源:主题目录下的 templates/ 与 parts/ 文件,以及数据库里 wp_template、wp_template_part 两种文章类型。在站点编辑器里做过的修改会写入数据库,且数据库版本优先于主题文件——这正是”改了文件没反应”的根源。

样式则主要来自 theme.json,核心通过 wp_get_global_stylesheet() 把 settings 与 styles 编译成内联 CSS 输出,style.css 在块主题里多数只承担元信息声明。子主题的 theme.json 会与父主题做深度合并:子主题声明的字段覆盖父主题同名字段,预置项(如调色板、字号)按 slug/name 归并。

改动类型 放置位置 优先级说明
整体版式(首页/单页) 子主题/templates/*.html 子主题文件 > 父主题文件,但均低于数据库自定义模板
页头页脚区块 子主题/parts/*.html 同上
颜色、字号、间距 子主题/theme.json 的 settings/styles 父子深度合并,子主题覆盖同名键
少量补充样式 子主题/style.css 或自定义 CSS 作为常规样式加载,命中同一选择器时按加载顺序决定
功能代码 子主题/functions.php 与经典主题一致,子主题先于父主题加载

保姆级实操

  1. 建子主题目录并写 style.css:头部必须有 Template: 指向父主题目录名,块主题同样依赖这个字段识别父子关系。
  2. 写 theme.json:只声明你要覆盖的部分,不要整份复制父主题配置,否则父主题升级后的改进会被你的旧副本锁死。
  3. 覆盖模板文件:从父主题 templates/ 复制 index.html(或 single.html)到子主题同路径再改;需要覆盖页头页脚时,在站点编辑器里先”清除自定义修改”,否则文件不会生效。
  4. 确认数据库里没有同名自定义模板:用 WP-CLI 列出 wp_template 与 wp_template_part,有残留就删除后重新加载。
  5. 功能扩展照旧:functions.php 里照常 add_theme_support()、注册样式脚本,块主题并不排斥 PHP。
  6. 核对主题状态:用 wp theme list 确认父主题存在且子主题状态为 active,父主题缺失会直接报错。
/*
Theme Name:   TT4 Child
Template:     twentytwentyfour
Version:      1.0.0
Text Domain:  tt4-child
*/
/* 块主题的 style.css 通常只放真正需要额外加载的样式 */
.wp-block-navigation__responsive-container.is-menu-open {
    background-color: #1b1b1b;
}
{
    "$schema": "https://schemas.wp.org/trunk/theme.json",
    "version": 2,
    "settings": {
        "appearanceTools": true,
        "color": {
            "palette": [
                { "slug": "brand", "color": "#0f6fff", "name": "品牌蓝" },
                { "slug": "ink", "color": "#1b1b1b", "name": "墨黑" }
            ]
        },
        "typography": {
            "fontSizes": [
                { "slug": "small", "size": "0.9rem", "name": "小" },
                { "slug": "large", "size": "1.75rem", "name": "大" }
            ]
        },
        "layout": {
            "contentSize": "760px",
            "wideSize": "1180px"
        }
    },
    "styles": {
        "elements": {
            "link": { "color": { "text": "var(--wp--preset--color--brand)" } }
        }
    }
}
# 列出数据库里被站点编辑器改动过的模板/模板部件(这是"改文件无效"的元凶)
wp post list --post_type=wp_template --fields=ID,post_name,post_title
wp post list --post_type=wp_template_part --fields=ID,post_name,post_title

# 确认父子主题状态
wp theme list

常见踩坑

  • 以为父主题的 style.css 内容会被自动继承——块主题不排队父主题样式表,需要自己 wp_enqueue_style 引入。
  • 站点编辑器里改过页头,之后在子主题 parts/header.html 改文字完全无效,因为数据库版本优先。
  • theme.json 整份复制父主题,父主题升级后新增的预置项被旧配置屏蔽。
  • version 字段写错或 $schema 指向过旧,导致部分新属性不生效。
  • 案例:某站在站点编辑器里把页头导航改成了两行布局,随后开发人员在子主题 parts/header.html 反复调整、清缓存、换服务器都没效果。最后用 wp post list --post_type=wp_template_part 才发现数据库里躺着一条自定义记录,删除后文件修改立刻生效。
  • 父主题被删掉或目录名与 Template: 不一致,前台直接报 “The theme directory … does not exist”。
  • 在 theme.json 里写 custom 样式却忘了同步 settings.custom,编辑器里看不到对应的控制面板。

总结

块主题子主题的三条判断线:文件 vs 数据库(数据库优先)、theme.json vs style.css(全局设置走前者,补丁样式走后者)、子主题 vs 父主题(深度合并,子覆盖父)。行动清单:① 先查数据库里有没有自定义模板;② theme.json 只写差异;③ 需要父主题样式就显式排队;④ 升级父主题后复查 theme.json 字段是否仍兼容。想系统理解模板查找机制的读者可看 WordPress 模板层级,子主题基础写法见 WordPress 子主题制作,样式入口的选择也可参考 主题自定义 CSS 放置位置。

U
UFO_PF作者

专注 WordPress 生态的实战作者,内容以「可复制、可验证」为第一原则。

留下你的想法

邮箱地址不会被公开。带 * 的为必填项。