WordPressの子テーマの作り方
WordPressの子テーマを作成して、親テーマの更新後もカスタマイズを維持する方法を解説。クラシックテーマとブロックテーマの設定、スタイル読み込み、テンプレートの上書きを紹介します。
WordPressの子テーマを作成するには、wp-content/themes に新しいフォルダーを追加し、その中に style.css を配置して有効化します。このとき、style.css の Template ヘッダーを親テーマのフォルダー名と一致させます。子テーマは親テーマのテンプレート、スタイル、機能を継承し、変更点だけを保持します。
テーマのファイルを直接編集し、次のアップデートで変更が消えてしまった経験があるなら、子テーマを使えばその問題を防げます。
本ガイドでは、最新のWordPressで機能するセットアップ方法を解説します。正しいエンキュー方法を用いたクラシックテーマの子テーマ、テンプレートと関数のオーバーライド、Twenty Twenty-Fourのようなブロックテーマで変わる点、そして子テーマがそもそも不要なケースを順に取り上げます。
重要なポイント
- 子テーマで必須のファイルは
style.cssだけです。そのTemplateヘッダーは親テーマのフォルダー名と完全に一致している必要があり、Twenty Twenty-Fourの場合の値はtwentytwentyfourです。 - 子テーマの
functions.phpは親テーマのものを置き換えません。WordPressは両方を読み込み、子テーマのファイルが先に実行されます。 - 子テーマのスタイルは
@importではなく、wp_enqueue_scriptsフックでwp_enqueue_style()を使って読み込みます。 - テンプレート、テンプレートパーツ、パターンをオーバーライドするには、同じ名前のファイルを子テーマに配置します。ブロックパターンの場合は、
Slugも同じにする必要があります。 - カスタム投稿タイプなど、テーマを切り替えても維持すべき変更は、子テーマではなくプラグインに実装します。
親テーマを直接編集するとなぜ問題になるのか
テーマがアップデートされると、WordPressはそのファイルを新しいバージョンで置き換えるため、テーマフォルダー内で行った編集はすべて失われます。子テーマを使えば、アップデートの影響を受けない別のフォルダーに変更を保持できます。Theme Handbookの子テーマガイドでは、独自の編集を失わずに親テーマのアップデートを適用する方法として、子テーマが紹介されています。なお、テーマシステムは親と子の2階層までで、その上に孫テーマをインストールすることはできません。
WordPressで子テーマを作成する方法(クラシックテーマ)
クラシックテーマの子テーマに必要なのは、フォルダー、Template ヘッダーを含む style.css、そして多くの場合はスタイルシートをエンキューする functions.php です。構成は、Bootstrapを使ったレスポンシブなWordPressテーマ構築ガイドで説明しているフォルダー、style.css、functions.php の構造と同じです。違いは、子テーマには変更する部分だけを含めるという点です。
wp-content/themes/
├── twentytwentyfour/
└── tt4-child/
├── style.css
└── functions.php
style.cssのヘッダー
厳密に必須なのは style.css だけです。Main Stylesheetのドキュメントによると、すべてのテーマには少なくとも Theme Name ヘッダーが必要で、子テーマではそれに加えて Template を指定します。
/*
* Theme Name: TT4 Child
* Template: twentytwentyfour
* Version: 1.0.0
* Text Domain: tt4-child
*/
Template には、親テーマの表示名ではなくフォルダー名を指定します。1文字でも一致しなければ、WordPressは子テーマを親テーマに関連付けません。
@importではなくスタイルシートをエンキューする
子テーマのスタイルは、@import ではなく、wp_enqueue_scripts フックで wp_enqueue_style() を使って読み込みます。古いチュートリアルの多くは、子テーマの style.css の先頭で @import を使って親テーマのスタイルを読み込んでいますが、この方法はすでに時代遅れです。
/* Outdated: do not use */
@import url("../twentytwentyfour/style.css");
ブラウザーは子テーマのスタイルシートをダウンロードして解析した後でなければ、インポートされたファイルを見つけられません。そのため2つのリクエストが順番に発生し、どちらもレンダリングをブロックします。また、インポートはWordPressのエンキューシステムの外にあるため、WordPressは依存関係の管理、バージョン付与、重複排除を行えません。
代わりに、wp_enqueue_scripts にフックした関数から wp_enqueue_style() を呼び出します。このフックはスクリプトの読み込みにも使われます。詳しくはWordPressテーマにカスタムJavaScriptを追加する方法の記事を参照してください。
<?php
// functions.php
add_action( 'wp_enqueue_scripts', 'tt4child_enqueue_styles' );
function tt4child_enqueue_styles() {
wp_enqueue_style(
'tt4child-style',
get_stylesheet_uri(), // the active (child) theme's style.css
array(), // $deps: handles that must load first
'1.0.0' // $ver: appended as a cache-busting query string
);
}
子テーマに適したエンキューコードは、親テーマがすでに何をエンキューしているかによって異なります。
| 親テーマがエンキューするもの | 子テーマで行うこと |
|---|---|
| 自身と子テーマの両方のスタイルシート | 何もしない |
| 自身のスタイルシートのみ | get_stylesheet_uri() で子テーマをエンキューする(上記のコード) |
get_stylesheet_uri() によるアクティブテーマのスタイルシートのみ | get_parent_theme_file_uri( 'style.css' ) で親テーマをエンキューする |
| 何もしない(Handbookによると、Twenty Twenty-Four) | get_stylesheet_uri() で子テーマをエンキューする |
3行目のケースでは、次のコードを使います。
function tt4child_enqueue_styles() {
wp_enqueue_style(
'tt4child-parent-style',
get_parent_theme_file_uri( 'style.css' )
);
}
どのケースに該当するかを調べるには、親テーマの functions.php で wp_enqueue_style を検索するか、ページのソースでスタイルシートの <link> タグを確認します。スタイルシートの読み込み順序は固定されておらず、エンキュー呼び出しの順序に従います。$deps 引数には、先に読み込む必要がある登録済みハンドルの配列を指定します。子テーマのスタイルを親テーマの後に出力するには、親テーマのコードからハンドル名を確認し、それを $deps に渡します。子テーマのスタイルシートURLが間違っていると、リクエストは404を返し、ページは親テーマのCSSだけでレンダリングされます。視覚的な再生と並べてネットワークリクエストを記録するセッションリプレイを使えば、失敗したリクエストとスタイルの当たっていないページを同時に確認できます。
親テーマのテンプレートをオーバーライドするには
親テーマのテンプレートをオーバーライドするには、ファイルを(移動ではなく)コピーして、子テーマ内の同じ相対パスに配置します。WordPressはテンプレート階層を処理する際に親テーマより先に子テーマのフォルダーを確認するため、子テーマにある同名のファイルが使用されます。コピーではなく移動してしまうと親テーマを変更することになり、いずれにせよ次のアップデートで元に戻ります。
twentytwentyfour/page.php → copy to → tt4-child/page.php
テンプレートパーツにも同じルールが適用されます。また、親テーマにない新しいテンプレートを追加することもできます。
親テーマの関数をオーバーライドする
子テーマの functions.php は親テーマのものを置き換えません。Handbookによると、WordPressは両方のファイルを実行し、子テーマのファイルを先に読み込んだ直後に親テーマのファイルを読み込みます。この読み込み順序から、2つのことが言えます。function_exists() で囲まれた親テーマの関数(プラガブル関数)は、子テーマで再定義できます。それ以外の親テーマの関数は、フックを解除するか、処理を追加する形で対応する必要があります。また、親テーマの functions.php のコードを子テーマに貼り付けてはいけません。同じ関数名を2回宣言すると、致命的エラーでサイトが停止します。
親テーマのプラガブル関数は次のようになっています。
// Parent theme
if ( ! function_exists( 'parenttheme_credit' ) ) {
function parenttheme_credit() { /* ... */ }
}
子テーマが先に実行されるため、子テーマで同じ名前の関数を定義すると、親テーマのバージョンはスキップされます。
// Child theme
function parenttheme_credit() {
echo '<p>Custom credit line</p>';
}
関数がプラガブルでない場合は、remove_action() を使い、登録時と同じフックと優先度を指定して削除します。子テーマのファイルのトップレベルに remove_action() を記述すると、親テーマがフックを追加する前に実行されるため、削除する対象がまだ存在しません。両方のテーマの functions.php が読み込まれた後に実行される after_setup_theme から呼び出してください。
// Parent theme
add_action( 'init', 'parenttheme_setup_extra', 20 );
// Child theme
add_action( 'after_setup_theme', function () {
remove_action( 'init', 'parenttheme_setup_extra', 20 );
} );
フィルターの場合も、remove_filter() が同じように機能します。親テーマの関数を置き換えるのではなく処理を追加したい場合は、同じフックに後の優先度で独自の関数を登録します。add_action() のデフォルトの優先度は10で、数値が大きいほど後に実行されます。
add_action( 'parent_footer', 'tt4child_footer_extra', 20 );
ブロックテーマの子テーマはどのように機能するのか
Twenty Twenty-Fourをベースにしたものなど、ブロックテーマの子テーマでは、多くの場合 style.css と theme.json だけで十分です。スタイルは主に theme.json で定義されるため、Handbookでは style.css のエンキューは不要な場合が多いとされており、functions.php をまったく持たないブロックテーマの子テーマも少なくありません。
| クラシックテーマの子テーマ | ブロックテーマの子テーマ | |
|---|---|---|
| 必須ファイル | style.css | style.css |
| スタイルの定義場所 | style.css(エンキューする) | theme.json |
functions.php | 通常は必要(エンキュー用) | 不要な場合が多い |
| テンプレート | テーマのルートにある .php ファイル | templates/ 内の .html ファイル |
| テンプレートパーツ | header.php などの .php ファイル | parts/ 内の .html ファイル |
| パターン | patterns/ 内のPHPファイルまたは register_block_pattern() | patterns/ 内のPHPファイル |
tt4-child/
├── style.css
├── theme.json
├── templates/
│ └── single.html
├── parts/
│ └── header.html
└── patterns/
└── (same filename as the parent pattern).php
テンプレート、パーツ、パターンをオーバーライドするには、同じ名前のファイルを追加します。パターンの場合は、登録された Slug ヘッダーも親テーマのものと一致させる必要があるため、親テーマのファイルからコピーしてください。
<?php
/**
* Title: Footer
* Slug: parent-slug/pattern-name
*/
?>
最小限の theme.json ではスキーマを固定し、WordPress 6.6以降が必要なバージョン3を使用します。
{
"$schema": "https://schemas.wp.org/wp/6.6/theme.json",
"version": 3,
"styles": {
"typography": {
"lineHeight": "1.7"
}
}
}
親テーマと子テーマの theme.json は特定のマージルールに従って統合され、子テーマの値が優先されます。また、サイトエディターで保存したカスタマイズはデータベースに保存され、Handbookのレイヤーモデルでは子テーマよりも上位に位置します。子テーマのテンプレートが反映されないように見える場合は、サイトエディターでそのテンプレートに保存されたカスタマイズをクリアしてください。
子テーマが不要なケース
ちょっとした見た目の調整や機能の追加であれば、子テーマは必要ありません。クラシックテーマでは、数行のルールならカスタマイザーの「追加CSS」で十分です。ブロックテーマが有効な場合は、代わりにサイトエディターのスタイルパネルからカスタムCSSを追加します。カスタム投稿タイプなどの機能的な変更はプラグインに実装すれば、テーマを切り替えた後も動作し続けます。変更が大きくなりすぎて子テーマの管理が難しくなった場合、Handbookでは親テーマをフォークして独自のテーマにすることを推奨しています。
まとめ
子テーマの本質は、1つのフォルダーと、Template の値が親テーマのフォルダー名と一致する style.css だけです。クラシックテーマでは、親テーマが読み込むものに合わせたエンキューコードを追加します。ブロックテーマでは、theme.json と同名のテンプレートファイルがその役割を担います。まずは親テーマがどのスタイルシートをエンキューしているかを確認し、実際に変更が必要なファイルだけを追加しましょう。
よくある質問
子テーマにおけるget_template_directory_uri()とget_stylesheet_directory_uri()の違いは何ですか?
子テーマが有効な場合、get_template_directory_uri()は親テーマのディレクトリURLを返し、get_stylesheet_directory_uri()は子テーマのディレクトリURLを返します。子テーマに保存したファイルにはstylesheet系の関数を使用してください。WordPress 4.7以降では、get_theme_file_uri()を使うほうが適している場合が多くあります。この関数は、子テーマにファイルのコピーがあればそれを返し、なければ親テーマのファイルにフォールバックします。
子テーマを有効化した後、カスタマイザーの設定とメニューの位置が消えてしまったのはなぜですか?
WordPressはカスタマイザーの設定(テーマ modification、theme mods)をテーマごとに、アクティブなテーマのフォルダー名をキーとして個別に保存します。そのため、子テーマは空の設定から始まり、親テーマの設定を継承しません。メニュー自体は残っていますが、メニューの位置に再度割り当て、その他の設定も再入力またはインポートする必要があります。親テーマの設定はデータベースに残っているため、親テーマに切り替えれば元に戻ります。
子テーマにコピーしたテンプレートファイルは、親テーマがアップデートされるとどうなりますか?
子テーマのコピーは保存した状態のまま残り、WordPressは親テーマの更新されたファイルの代わりに引き続きそれを使用します。親テーマがそのファイルに加えたバグ修正、セキュリティパッチ、マークアップの変更は、オーバーライドしたファイルには一切反映されません。親テーマをアップデートするたびに、オーバーライドしたファイルを新しい親テーマのバージョンと比較し、必要な変更をマージしてください。管理しやすくするため、オーバーライドするファイルはできるだけ少なくしましょう。
コードを書かずにブロックテーマの子テーマを作成できますか?
はい、できます。WordPress.orgで公開されている公式プラグインCreate Block Themeには、Create Child Themeオプションがあります。このオプションは、Twenty Twenty-Fourなどアクティブなブロックテーマの子テーマを生成し、サイトエディターで行った変更を子テーマのファイルに書き出します。このプラグインはブロックテーマ向けに作られているため、クラシックテーマを親とする子テーマでは、上記で説明したstyle.cssとfunctions.phpのセットアップが引き続き必要です。
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