WordPress theme.json 完整解析:settings、styles 與階層覆蓋順序
搞懂 theme.json 裡 settings 與 styles 各自負責什麼,並依照 WordPress 的階層覆蓋順序,修好那些改了卻完全沒反應的區塊佈景主題設定。
發布於
theme.json 是放在區塊佈景主題根目錄的單一設定檔,它同時做兩件互相獨立的事:settings 決定區塊編輯器要提供哪些選項給使用者,styles 決定網站預設看起來是什麼樣子。WordPress 會解析它,和自己的預設值以及網站編輯器裡儲存的內容合併,最後在每一個頁面輸出成 CSS 自訂屬性加上一段行內樣式表。
把這兩件事搞混,就是絕大多數 theme.json 改了卻沒反應的原因。在 settings 底下宣告一個顏色,不會把那個顏色套用到任何地方,它只是建立了一個變數,以及編輯器側邊欄裡的一個色票。
最上層有哪些鍵
一個最精簡的檔案長這樣:
{
"$schema": "https://schemas.wp.org/trunk/theme.json",
"version": 3,
"settings": {},
"styles": {},
"templateParts": [],
"customTemplates": []
}
| 鍵 | 作用 |
|---|---|
$schema | 只提供程式編輯器的自動完成與驗證,WordPress 會忽略它。 |
version | 告訴 WordPress 用哪一套結構解析,不是你的佈景主題版本。 |
settings | 產生 CSS 變數,並控制編輯器開放哪些選項。 |
styles | 真正套用預設樣式。 |
templateParts | 宣告 parts/ 裡的組件,以及它們屬於哪個區域。 |
customTemplates | 把 templates/ 裡的頁面範本註冊到文章編輯器。 |
version 常讓人誤會,因為它看起來像佈景主題的版本號。它不是。它選的是解析模式,而舊版 WordPress 會默默忽略它不認識的結構所帶來的鍵。如果你要支援舊站台,就以那些站台看得懂的版本為目標,不要假設新的鍵會優雅降級。撰文當下版本 3 是最新的;版本 2 仍然被大量使用,也仍然能被正常解析。
$schema 指向 WordPress 託管的結構描述網址。把它指到 trunk 能在你的程式編輯器裡拿到最新的提示;如果你是刻意停在較舊的結構,用指定版本的網址會更保險。
settings:編輯器提供什麼
settings 底下的每一項都會產生一個 CSS 自訂屬性,而且多數情況下還會產生一個編輯器控制項。但 settings 底下的任何東西都不會套用樣式。
{
"settings": {
"color": {
"palette": [
{ "slug": "brand", "color": "#1f4ed8", "name": "Brand" },
{ "slug": "ink", "color": "#111827", "name": "Ink" }
],
"custom": false
},
"typography": {
"fontSizes": [
{ "slug": "small", "size": "0.875rem", "name": "Small" },
{ "slug": "large", "size": "1.5rem", "name": "Large" }
]
},
"layout": {
"contentSize": "680px",
"wideSize": "1200px"
}
}
}
上面這段會依照預設值的路徑與 slug 產生對應的變數:
--wp--preset--color--brand
--wp--preset--color--ink
--wp--preset--font-size--small
--wp--preset--font-size--large
它同時會產生像 .has-brand-color 和 .has-brand-background-color 這類工具類別,編輯器就是靠這些類別把使用者選的色票套到區塊上。
"custom": false 這一行代表 settings 的另一半功能:把選項關掉。設了它,任意取色器就會消失,使用者只剩下你給的調色盤。同樣的模式在各處都適用,例如 settings.typography.customFontSize、settings.spacing.customSpacingSize、settings.border 等等。settings 底下沒有任何一個鍵是裝飾用的;每個鍵不是新增變數、新增控制項,就是移除控制項。
settings.custom 是給你自己放變數的自由欄位:
{
"settings": {
"custom": {
"lineHeight": { "body": 1.6 },
"shadow": { "card": "0 1px 3px rgba(0,0,0,0.12)" }
}
}
}
它們會變成 --wp--custom--line-height--body 和 --wp--custom--shadow--card。注意這個轉換規則:駝峰式的鍵會被拆成短橫線形式,巢狀層級之間用兩個短橫線串接。變數名稱寫錯,是值默默退回預設的常見原因。
你也可以針對個別區塊設定,這就是「按鈕可以自由選色、段落不行」的做法:
{
"settings": {
"blocks": {
"core/paragraph": {
"color": { "custom": false, "customGradient": false }
}
}
}
}
styles:真正被算繪出來的東西
styles 才是值真正被套用的地方。它的結構對應編輯器的架構:先是根層級,再來是 elements,最後是 blocks。
{
"styles": {
"color": {
"background": "var(--wp--preset--color--base)",
"text": "var(--wp--preset--color--ink)"
},
"typography": {
"lineHeight": "var(--wp--custom--line-height--body)"
},
"elements": {
"link": {
"color": { "text": "var(--wp--preset--color--brand)" },
":hover": { "typography": { "textDecoration": "none" } }
}
},
"blocks": {
"core/quote": {
"typography": { "fontStyle": "italic" },
"spacing": { "padding": { "left": "var(--wp--preset--spacing--40)" } }
}
}
}
}
根層級的 styles 會落在 body 上。elements 涵蓋的是那些不是區塊的 HTML 基本元素,例如連結、按鈕、標題、圖說。blocks 則是用名稱指定某一種區塊。
必須誠實說明的限制:styles 沒辦法表達 CSS 能做的所有事。你不能自己寫媒體查詢,沒有複雜選擇器,沒有動畫,支援的偽類狀態也只有一小組。流動式字級和以版面為基礎的尺寸設定,涵蓋了過去很多人用斷點處理的情境,但不是全部。多數正式出貨的區塊佈景主題都是 theme.json 再加一份不大的樣式表,這是正常結果,不是失敗。
settings 與 styles 的經典陷阱
最常見的求助問題,幾乎都是「我把品牌色加進去了,可是什麼都沒變」的各種版本。
沒錯,本來就不會變。把它加進 settings.color.palette,只是建立了 --wp--preset--color--brand 和一個色票,什麼都沒套用。要讓它成為預設的連結顏色,你必須另外寫進 styles:
{
"settings": {
"color": {
"palette": [{ "slug": "brand", "color": "#1f4ed8", "name": "Brand" }]
}
},
"styles": {
"elements": {
"link": { "color": { "text": "var(--wp--preset--color--brand)" } }
}
}
}
可以這樣記:settings 是你交到使用者手上的那盒顏料,styles 是你在他們進場之前先刷好的那層漆。
覆蓋順序,由低到高
這一段能解釋為什麼有些網站看起來「無視」佈景主題檔案。WordPress 在輸出 CSS 之前,會先合併好幾層:
- WordPress 核心預設值 — 核心自己就帶了一份
theme.json,內含基礎調色盤、字級與間距級距。 - 父佈景主題的
theme.json - 子佈景主題的
theme.json— 逐鍵合併到父主題之上,不是整份檔案取代掉。 - 儲存在資料庫裡的全域樣式 — 也就是網站編輯器「樣式」面板寫入的內容。
- 個別區塊上的樣式 — 儲存在文章內容裡的屬性,最後算繪成行內樣式或類別。
會把網站搞壞的是第 4 層。只要有人打開「樣式」面板並儲存,WordPress 就會存下一筆全域樣式記錄,而這筆記錄在它涵蓋的每個屬性上都會贏過你的檔案。之後你再怎麼改 theme.json,那些屬性都不會有任何可見變化。於是你會看到:部署完網站長得一模一樣,但磁碟上的檔案明明就不同。
正確的做法是清掉那筆已儲存的記錄,而不是用 !important 硬碰硬。打開網站編輯器,進入「樣式」,開啟修訂紀錄面板,重設回佈景主題預設值。動手前請先跟客戶或網站擁有者確認,因為重設會捨棄他們做過的自訂,這是實際的代價,不是免費的操作。
第二個嫌疑犯是快取。WordPress 會把解析後的 theme.json 資料快取起來,而不是每次請求都重讀檔案。這在正式環境正是你要的,在開發時卻正是你不要的。啟用 WP_DEBUG,或使用新版提供的佈景主題開發模式設定,都會讓 WordPress 每次重新讀取檔案。如果你的修改只有在部署或清快取之後才出現,看到的就是這個現象。
templateParts 與 customTemplates
這兩個都是陣列,用來描述你佈景主題裡已經存在的檔案。
{
"templateParts": [
{ "name": "header", "title": "Header", "area": "header" },
{ "name": "footer", "title": "Footer", "area": "footer" }
],
"customTemplates": [
{ "name": "page-wide", "title": "Wide Page", "postTypes": ["page"] }
]
}
name 對應的是不含副檔名的檔名,例如 parts/header.html、templates/page-wide.html。area 這個值很重要:它決定該組件會不會被包在頁首或頁尾的地標元素裡,也決定編輯器怎麼分類它。不填的話,這個組件就會被當成未分類。
customTemplates 是讓範本出現在文章編輯器範本下拉選單裡的關鍵。少了這筆設定,檔案雖然存在,卻沒有人能選到它。
一套快速的排查順序
當區塊佈景主題的呈現和檔案裡寫的不一致時,先照這個順序走一遍,再動手改任何東西:
- 檢視原始碼,搜尋產生出來的全域樣式區塊。如果你的變數不在裡面,問題出在
settings,或是 slug 拼錯了。 - 如果變數在,但沒有被用到,問題是少了對應的
styles設定。 - 如果兩邊都在,卻被某個東西蓋掉,去檢查有沒有已儲存的全域樣式記錄。
- 到這一步才去看你自己的樣式表、外掛,或某個在覆蓋順序更後面注入 CSS 的頁面編輯器。
FAQ
常見問題
WordPress 的 theme.json 是什麼?
它是放在區塊佈景主題根目錄的單一 JSON 設定檔,負責兩件事:決定區塊編輯器要開放哪些設計選項給使用者,以及決定預設樣式長什麼樣子。WordPress 會讀取它,從中產生 CSS 自訂屬性與一份樣式表,再和核心預設值、使用者在網站編輯器儲存的全域樣式合併在一起。
theme.json 裡的 settings 和 styles 差在哪?
settings 決定「有哪些東西可以用」,它會產生 CSS 變數和編輯器控制項,但本身不會套用任何樣式。styles 才是真正把值套上去的地方,而且是透過那些變數來套。把一個顏色加進調色盤,在你另外寫進 styles 或使用者自己在編輯器裡挑選之前,畫面上不會有任何改變。
為什麼我改了 theme.json,前台卻看不到效果?
幾乎都是因為資料庫裡儲存的全域樣式蓋過了 theme.json。只要有人動過網站編輯器的「樣式」面板並儲存,那筆記錄就會在它涵蓋的每個屬性上勝出。請開啟「樣式」,用修訂紀錄面板重設回佈景主題預設值,再重新載入頁面。第二個嫌疑犯是 theme.json 解析結果的快取。
有了 theme.json,還需要 style.css 嗎?
需要。WordPress 靠 style.css 開頭的註解標頭取得佈景主題名稱、版本等中繼資料,沒有它,佈景主題根本不會被辨識。你可以讓它除了標頭以外完全空白,把設計決策都放進 theme.json,也可以留一小段 CSS 處理 theme.json 表達不出來的東西。
theme.json 的 version 該填多少?
填你所支援的最低 WordPress 版本看得懂的最高數字。version 這個鍵是在告訴 WordPress 要用哪一套結構去解析,而舊版 WordPress 會直接忽略它不認得的鍵。如果你要支援舊站台,就停在那些站台支援的版本,別假設新的鍵會優雅降級。
theme.json 可以完全取代 CSS 嗎?
不行。它很擅長處理預設值、區塊預設樣式、元素樣式、版面寬度和間距,但它沒有讓你自己撰寫媒體查詢的機制,也不支援複雜選擇器、動畫,以及它內建支援之外的偽類狀態。多數正式上線的區塊佈景主題都是 theme.json 搭配一份不大的樣式表。