跳至內容
佈景主題

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/ 裡的組件,以及它們屬於哪個區域。
customTemplatestemplates/ 裡的頁面範本註冊到文章編輯器。

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.customFontSizesettings.spacing.customSpacingSizesettings.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 之前,會先合併好幾層:

  1. WordPress 核心預設值 — 核心自己就帶了一份 theme.json,內含基礎調色盤、字級與間距級距。
  2. 父佈景主題的 theme.json
  3. 子佈景主題的 theme.json — 逐鍵合併到父主題之上,不是整份檔案取代掉。
  4. 儲存在資料庫裡的全域樣式 — 也就是網站編輯器「樣式」面板寫入的內容。
  5. 個別區塊上的樣式 — 儲存在文章內容裡的屬性,最後算繪成行內樣式或類別。

會把網站搞壞的是第 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.htmltemplates/page-wide.htmlarea 這個值很重要:它決定該組件會不會被包在頁首或頁尾的地標元素裡,也決定編輯器怎麼分類它。不填的話,這個組件就會被當成未分類。

customTemplates 是讓範本出現在文章編輯器範本下拉選單裡的關鍵。少了這筆設定,檔案雖然存在,卻沒有人能選到它。

一套快速的排查順序

當區塊佈景主題的呈現和檔案裡寫的不一致時,先照這個順序走一遍,再動手改任何東西:

  1. 檢視原始碼,搜尋產生出來的全域樣式區塊。如果你的變數不在裡面,問題出在 settings,或是 slug 拼錯了。
  2. 如果變數在,但沒有被用到,問題是少了對應的 styles 設定。
  3. 如果兩邊都在,卻被某個東西蓋掉,去檢查有沒有已儲存的全域樣式記錄。
  4. 到這一步才去看你自己的樣式表、外掛,或某個在覆蓋順序更後面注入 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 搭配一份不大的樣式表。