本文へスキップ
テーマ

theme.json 完全解説:settings と styles、そしてカスケードの仕組み

theme.json の settings と styles が別々の役割を持つ理由を理解し、WordPress のカスケードをたどってブロックテーマの編集が反映されない問題を解決します。

公開

theme.json は、ブロックテーマのルートに置かれる 1 つの設定ファイルで、まったく別の 2 つの仕事をします。settings はブロックエディターがユーザーに何を提供するかを決め、styles はサイトがデフォルトでどう見えるかを決めます。WordPress はこれを解析し、自身のデフォルト値やサイトエディターで保存された内容とマージして、その結果を CSS カスタムプロパティとインラインスタイルシートとして全ページに出力します。

この 2 つの役割を混同することが、theme.json の編集が何も効いていないように見える最大の原因です。settings に色を宣言しても、その色はどこにも適用されません。変数と、エディターのサイドバーに表示される色見本が生まれるだけです。

トップレベルのキー

最小構成のファイルはこうなります。

{
  "$schema": "https://schemas.wp.org/trunk/theme.json",
  "version": 3,
  "settings": {},
  "styles": {},
  "templateParts": [],
  "customTemplates": []
}
キー役割
$schemaコードエディターの補完と検証のためだけのもの。WordPress は無視します。
versionどのスキーマ形式で解析するかを指定。テーマのバージョンではありません。
settingsCSS 変数を生成し、エディターに何を出すかを制御します。
styles実際のデフォルトスタイルを適用します。
templatePartsparts/ 内のパーツと、それが属するエリアを宣言します。
customTemplatestemplates/ 内のページテンプレートを投稿エディター向けに登録します。

version はテーマのバージョン番号に見えるせいで、よく誤解されます。そうではありません。これは解析モードを選ぶもので、古い WordPress は知らないスキーマ形式のキーを黙って無視します。古い環境をサポートするなら、新しいキーが安全に無視されることを期待するのではなく、その環境が理解できるバージョンに合わせてください。執筆時点ではバージョン 3 が最新で、バージョン 2 も依然として広く使われ、解析もされます。

$schema は WordPress がホストするスキーマ URL を指します。trunk を指定すればコードエディターで最新のヒントが得られますが、意図的に古いスキーマに留まるなら、バージョン固定の URL のほうが安全です。

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"
    }
  }
}

これで、プリセットのパスとスラッグから命名された変数が生成されます。

--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 の下に飾りのキーは 1 つもありません。どのキーも、変数を追加するか、コントロールを追加するか、コントロールを取り除くかのいずれかです。

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 になります。変換規則に注意してください。キャメルケースのキーはケバブケースに分解され、入れ子はダッシュ 2 つでつながれます。変数名を間違えることは、値が黙ってフォールバックする典型的な原因です。

設定はブロックごとにスコープを絞れます。ボタンにはカラーピッカーを許可し、段落には許可しない、といったことがこれで実現できます。

{
  "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.html)。area の値は重要で、そのパーツがヘッダーやフッターのランドマーク要素で包まれるか、エディターでどう分類されるかを決めます。省略すると、そのパーツは未分類として扱われます。

customTemplates は、投稿エディターのテンプレート選択にそのテンプレートを表示させるためのものです。この記述がないと、ファイルは存在しても誰も選べません。

手早い切り分けの順番

ブロックテーマがファイルの記述どおりにスタイリングされないときは、何かに手を付ける前にこの順で確認します。

  1. ソースを表示して、生成されたグローバルスタイルのブロックを探します。変数がそこになければ、問題は settings か、スラッグの打ち間違いです。
  2. 変数はあるのに使われていなければ、styles の記述が足りていません。
  3. 両方あるのに何かに上書きされているなら、保存されたグローバルスタイルのレコードを確認します。
  4. そこまで済んでから、自前のスタイルシート、プラグイン、カスケードの後ろで CSS を注入するページビルダーを見ます。

FAQ

よくある質問

WordPress の theme.json とは何ですか?

ブロックテーマのルートに置かれる 1 つの JSON 設定ファイルで、2 つのことを制御します。ブロックエディターがユーザーにどのデザイン項目を見せるか、そしてデフォルトのスタイルがどうなるか、です。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 に置いてもよいですし、theme.json では表現できない部分のために少量の CSS を残しても構いません。

theme.json のバージョン番号は何を指定すべきですか?

サポート対象の最も古い WordPress が理解できる範囲で、最も高いバージョンを指定します。version キーは、どのスキーマ形式で解析するかを WordPress に伝えるもので、古い WordPress は認識できないキーを黙って無視します。古い環境をサポートするなら、新しいキーがうまく劣化してくれると期待せず、その環境が対応するバージョンに合わせてください。

theme.json があれば CSS は不要になりますか?

なりません。プリセット、ブロックのデフォルト、要素のスタイル、レイアウト幅や余白はよくカバーしますが、自分で書くメディアクエリ、複雑なセレクター、アニメーション、対応している一部を超える擬似クラスの状態という概念はありません。実運用のブロックテーマの多くは、theme.json に加えて控えめなスタイルシートを同梱しています。