WordPress theme.json 文件包含哪些内容
了解WordPress theme.json文件的内容、settings和styles如何生成CSS变量,以及预设、自定义CSS和子主题的工作方式。
WordPress 的 theme.json 是位于块主题(block theme)根目录下的 JSON 文件。它集中声明主题的设计令牌(design tokens),包括颜色、字号、字体族、间距和布局宽度,让块编辑器和前端读取同一套值。
如果你用过设计令牌流水线,这个文件乍看会很眼熟。但当你想找到它生成的 CSS,或者想弄清为什么子主题把一半调色板都清空了时,就会发现它有不少特别之处。本文逐一讲解该文件的各个部分,展示 WordPress 由此生成的 CSS,说明如何在自己的样式表中使用这些变量,并指出哪些场景仍需手写 CSS。文中所有示例均使用 WordPress 6.6 引入的 schema 版本 3。
核心要点
theme.json有两个主要顶级键:settings决定编辑器提供哪些控件和预设,styles为页面、HTML 元素和各个区块设置默认值。- 除双色调(duotone)滤镜外,每个预设都会生成一个名为
--wp--preset--{category}--{slug}的 CSS 自定义属性。例如,slug 为ink的调色板颜色可以在任意样式表中以var(--wp--preset--color--ink)引用。 settings.custom下的值会生成--wp--custom--*属性:camelCase 转换为 kebab-case,每一层嵌套之间用双连字符分隔。- 子主题的
theme.json会与父主题合并并覆盖父主题的值,但子主题声明的任何预设列表都会整体替换父主题的对应列表。
什么是 theme.json?
theme.json 是块主题的设计令牌文件。你只需在其中声明一次颜色、排版、间距和布局宽度,WordPress 就会用这些值构建编辑器控件,并生成前端样式表。它的顶层结构很简洁:$schema、version、settings 和 styles。另外还有 customTemplates、templateParts 和 patterns,分别用于注册模板、模板部件以及 Pattern Directory 中的区块样板。
{
"$schema": "https://schemas.wp.org/trunk/theme.json",
"version": 3,
"settings": {},
"styles": {}
}
将 $schema 指向 trunk 版 theme.json schema,即可在 VS Code 中获得自动补全和校验。
为什么需要 theme.json?
过去,PHP 中的 add_theme_support() 标志、编辑器配置和前端 CSS 分散在三处,很容易彼此脱节。theme.json 把它们统一了起来。Block Editor Handbook 的全局设置指南列出了每个旧版 add_theme_support 标志对应的 theme.json 键。如果主题在两处设置了同一项,以 theme.json 中的值为准。
| add_theme_support | theme.json 对应项 |
|---|---|
editor-color-palette | settings.color.palette |
editor-font-sizes | settings.typography.fontSizes |
disable-custom-colors | settings.color.custom: false |
custom-units | settings.spacing.units |
appearance-tools | settings.appearanceTools: true |
settings 中包含什么?
settings 控制编辑器提供的功能,包括选择器中显示哪些预设,以及允许使用哪些自由输入控件。预设是对象数组,每个对象包含一个 slug、一个值和一个显示名称 name。
{
"$schema": "https://schemas.wp.org/trunk/theme.json",
"version": 3,
"settings": {
"appearanceTools": true,
"color": {
"custom": false,
"customGradient": false,
"defaultPalette": false,
"palette": [
{ "slug": "ink", "color": "#1b1f24", "name": "Ink" },
{ "slug": "accent", "color": "#3b5bdb", "name": "Accent" }
]
},
"typography": {
"customFontSize": false,
"defaultFontSizes": false,
"fontSizes": [
{ "slug": "small", "size": "0.875rem", "name": "Small" },
{ "slug": "large", "size": "1.5rem", "name": "Large" }
],
"fontFamilies": [
{ "slug": "system", "fontFamily": "-apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif", "name": "System" }
]
},
"spacing": { "blockGap": true, "units": ["px", "rem", "%"] },
"layout": { "contentSize": "720px", "wideSize": "1100px" },
"custom": { "radius": { "card": "12px" } }
}
}
将 color.custom、customGradient 和 customFontSize 设为 false 会移除自由选择器,编辑者只能从你定义的预设中选择。在版本 3 中,defaultFontSizes: false 尤为关键。theme.json 版本 3 开发说明指出:只有将 defaultFontSizes 或 defaultSpacingSizes 设为 false,v3 主题才能复用核心默认的字号和间距尺寸 slug,而 small 和 large 恰好都是核心 slug。appearanceTools: true 会启用一组设计工具,具体清单见 theme.json 实时参考文档。如果你要为 fontFamilies 加载 Web 字体,可参阅如何在 WordPress 中自托管 Google Fonts。
不同类型的预设会生成不同的输出:
| 键 | 生成内容 |
|---|---|
color.palette | 一个自定义属性,外加三个类(文本、背景、边框颜色) |
typography.fontSizes | 一个自定义属性,外加一个类 |
typography.fontFamilies | 一个自定义属性,外加一个类 |
spacing.spacingSizes | 仅一个自定义属性 |
custom | --wp--custom--* 属性 |
color.custom、customFontSize | 仅影响编辑器界面,不生成 CSS |
注意,theme.json 中有两个互不相关的 custom 键:settings.color.custom: false 用于隐藏颜色选择器;settings.custom 则是一个自由格式的对象,其中的值会转换为 CSS 变量。
layout.contentSize 和 wideSize 如何工作?
layout.contentSize 设置受约束布局(constrained layout)中内容的默认宽度,layout.wideSize 设置“宽幅”对齐区块的宽度。核心将这两个值以 --wp--style--global--content-size 和 --wp--style--global--wide-size 的形式暴露在 :root 上。此前它们声明在 body 上,Gutenberg PR #42084 将全局自定义属性移到了 :root。因此,自定义组件可以与区块网格对齐:
.site-banner {
max-width: var(--wp--style--global--wide-size);
margin-inline: auto;
}
styles 中包含什么?
styles 在三个层级上应用默认值:顶层属性作用于 body;elements 作用于 HTML 元素,例如 link(对应 a)以及 h1 到 h6;blocks 按名称作用于具体区块。Handbook 的 styles 章节对每个层级都有说明。
{
"$schema": "https://schemas.wp.org/trunk/theme.json",
"version": 3,
"styles": {
"color": { "text": "var(--wp--preset--color--ink)" },
"spacing": { "blockGap": "1.5rem" },
"blocks": {
"core/group": {
"color": { "text": "var(--wp--preset--color--accent)" },
"elements": {
"h2": { "typography": { "fontSize": "var(--wp--preset--font-size--large)" } }
}
}
}
}
}
输出:
body {
color: var(--wp--preset--color--ink);
}
:root :where(.wp-block-group) {
color: var(--wp--preset--color--accent);
}
:root :where(.wp-block-group h2) {
font-size: var(--wp--preset--font-size--large);
}
自 WordPress 6.6 起,:root :where() 包装将这些规则的优先级(specificity)固定在 0-1-0,与单个类选择器相同。之后加载的、优先级相同或更高的主题规则都会覆盖它们。link 和 button 元素还支持 ":hover"、":focus" 等伪状态键。
WordPress 会从 theme.json 生成哪些 CSS?
除双色调滤镜外,每个预设都会生成一个名为 --wp--preset--{category}--{slug} 的 CSS 自定义属性;会生成类的预设则遵循 .has-{slug}-{category} 的命名模式。settings.custom 下的值会生成 --wp--custom-- 属性。WordPress 会把 camelCase 键转换为 kebab-case,并在每层嵌套之间插入 --,因此 custom.lineHeight.body 会变成 --wp--custom--line-height--body。Handbook 的命名 FAQ 逐段拆解了这一命名规则。
基于上文的 settings 和 styles,全局样式表会包含类似如下的输出。Handbook 中的示例使用的是 body,但当前核心已改为在 :root 上声明这些属性,这一变更来自 Gutenberg PR #42084:
:root {
--wp--preset--color--ink: #1b1f24;
--wp--preset--color--accent: #3b5bdb;
--wp--preset--font-size--large: 1.5rem;
--wp--custom--radius--card: 12px;
--wp--style--block-gap: 1.5rem;
}
.has-accent-color { color: var(--wp--preset--color--accent) !important; }
根级的 styles.spacing.blockGap 值以 --wp--style--block-gap 的形式暴露。编辑者能否修改它,取决于 settings.spacing.blockGap 的取值:
| 值 | 区块间距控件 | 是否输出间距样式 |
|---|---|---|
true | 显示 | 是 |
false | 隐藏 | 是,theme.json 中设置的值仍然生效 |
null(默认) | 隐藏 | 否 |
这些都是普通的 CSS 自定义属性,任何样式表都可以使用:
.pricing-card {
background: var(--wp--preset--color--ink);
color: #fff;
border-radius: var(--wp--custom--radius--card);
padding: var(--wp--style--block-gap);
font-size: var(--wp--preset--font-size--large);
}
在 theme.json 中修改某个令牌后,这个组件会随之更新。由于 theme.json 的输出会被缓存,开发期间请在 wp-config.php 中将 WP_DEVELOPMENT_MODE 设为 'theme'。
theme.json 有哪些局限?子主题如何合并?
theme.json 只覆盖其 styles schema 中定义的属性,其他内容都需要写在 CSS 中:
- 非区块标记的布局,例如插件或第三方输出的内容
- 动画、过渡和关键帧
- 与区块或元素无关的任意选择器
- 超出现有样式属性范围的组件样式(使用 Bootstrap 构建响应式 WordPress 主题一文展示了以 CSS 为主的做法)
style.css 仍然必不可少,因为主题头信息就写在其中。对于子主题,Template 字段需填写父主题在 wp-content/themes 下的文件夹名,拼写必须完全一致,详见 Theme Handbook 的主样式表页面:
/*
Theme Name: Studio Child
Template: studio
*/
子主题的 theme.json 会与父主题合并并覆盖父主题的值,但子主题声明的任何预设列表都会整体替换父主题的对应列表。下面这个子主题文件会导致调色板中只剩一种颜色:
{
"$schema": "https://schemas.wp.org/trunk/theme.json",
"version": 3,
"settings": {
"color": {
"palette": [
{ "slug": "accent", "color": "#c2255c", "name": "Accent" }
]
}
}
}
如果只想修改 accent,需要复制完整的调色板,再编辑这一项:
{
"$schema": "https://schemas.wp.org/trunk/theme.json",
"version": 3,
"settings": {
"color": {
"palette": [
{ "slug": "ink", "color": "#1b1f24", "name": "Ink" },
{ "slug": "accent", "color": "#c2255c", "name": "Accent" }
]
}
}
}
在子主题的 theme.json 中,未声明的对象键仍会继承父主题的值。例如,子主题只设置了 styles.spacing.padding.top 和 bottom,父主题的左右内边距仍然保留。如果某个 slug 被丢弃,导致线上站点的内容回退到另一种颜色,而编辑器预览中却一切正常,可以对前端进行会话回放(session replay),查看是哪个元素、哪个模板丢失了该预设。
总结
theme.json 是一个令牌文件,WordPress 会将其编译为 CSS 自定义属性、工具类和低优先级的默认规则。预设放在 settings 中,默认样式放在 styles 中,其余内容写在 CSS 里,并引用生成的 --wp-- 变量。接下来,可以在使用你主题的页面上打开浏览器开发者工具,找到 global-styles-inline-css,将其中声明的属性与你的文件逐一比对。任何缺失的令牌都意味着 slug 或 schema 存在错误,最好在用户遇到问题之前修复。
常见问题
为什么我在 theme.json 中修改的值没有在网站上生效?
很可能是站点编辑器中已保存的自定义设置覆盖了它。当用户在「外观 > 编辑器」中修改样式时,WordPress 会将这些 JSON 保存到站点数据库中。根据 Theme Handbook 的说明,这份用户配置的优先级高于核心默认值、父主题的 theme.json 和子主题的 theme.json。请在样式面板中检查该令牌是否被自定义过,如有则将其重置,然后重新加载前端页面。
可以在 theme.json 中直接编写 CSS 吗?
可以。自 WordPress 6.2 起,theme.json 支持在 styles.css 中编写全局规则的 CSS 字符串,也支持在 styles.blocks 下某个区块的 css 属性中编写针对该区块的规则。区块级 CSS 会显示在样式面板中对应区块的设置里,用户可以对其进行编辑。用户的自定义 CSS 可能覆盖或移除以这种方式添加的主题 CSS,因此设计所依赖的关键规则应放在通过 enqueue 加载的样式表中。
传统 PHP 主题可以使用 theme.json 吗?
可以。传统主题可以包含 theme.json,用来配置块编辑器的设置和预设,而无需调用 add_theme_support,社区将这种方式称为混合主题(hybrid theme)。添加该文件并不会把主题变成块主题,因为只有包含 templates/index.html 的主题才会被 WordPress 视为块主题。如果主题仍保留部分 add_theme_support 调用,theme.json 中对应的设置将优先生效。
如何在 PHP 中读取 theme.json 的值?
使用 wp_get_global_settings() 读取设置,使用 wp_get_global_styles() 读取样式。两者都接受一个路径数组,例如 wp_get_global_settings( array( 'color', 'palette', 'theme' ) ) 只返回主题定义的调色板条目。传入包含 block_name 键的 context 数组,可将查询范围限定到单个区块。默认情况下,返回结果包含用户的自定义设置;如果只想获取核心和主题的值,可在 context 数组中将 origin 设为 'base'。
Gain Debugging Superpowers
Unleash the power of session replay to reproduce bugs, track slowdowns and uncover frustrations in your app. Get complete visibility into your frontend with OpenReplay — the most advanced open-source session replay tool for developers.
Star on GitHub12k