結論
WordPress テーマで PHP ファイルを読み込むときは、表示用の部品(テンプレートパーツ)は get_template_part()、関数やクラスの定義ファイルは require と使い分けます。
| 比べる点 | get_template_part() |
include / require |
|---|---|---|
| 子テーマでの上書き | できる(子テーマ → 親テーマの順に探す) | できない(書いたパスをそのまま読む) |
| 変数の受け渡し | $args(5.5.0 以降)で渡す。呼び出し元のローカル変数は見えない |
呼び出し元の変数がそのまま見える |
| ファイルが無いとき | 何も出力せず false を返す |
include は警告、require は致命的エラー |
| 名前の候補 | slug-name.php → slug.php と順に探す |
なし |
| 向いている用途 | ヘッダー以外の繰り返し部品(カード、ループの中身など) | functions.php から inc/*.php を読む |
get_template_part() のリファレンスは、この関数の目的を「子テーマが、テーマ内の再利用部分を上書きできる簡単な仕組みを提供する」と説明しています。
原因・仕組み
get_template_part( $slug, $name, $args ) は、{$slug}-{$name}.php と {$slug}.php の候補を作り、locate_template() に渡します。locate_template() は、有効なテーマ(子テーマ)のフォルダ → 親テーマのフォルダ → wp-includes/theme-compat/ の順にファイルを探し、最初に見つかったものを読み込みます。
読み込みは WordPress 内部の関数の中で行われるので、呼び出し元のローカル変数はテンプレートから見えません。WordPress 5.5.0 で第3引数 $args が追加され、配列で値を渡せるようになりました。読み込む前には get_template_part_{$slug} アクションが実行されます。
一方、include / require は PHP の構文なので、呼び出し元のスコープでファイルを実行し、子テーマの仕組みとは無関係です。
手順(サンプルコード)
テンプレートパーツを呼ぶ(値は $args で渡す)
// index.php など
while ( have_posts() ) {
the_post();
get_template_part( 'parts/card', get_post_type(), array( 'show_date' => true ) );
}
// parts/card.php
$show_date = ! empty( $args['show_date'] );
?>
<article <?php post_class( 'card' ); ?>>
<h2><a href="<?php the_permalink(); ?>"><?php the_title(); ?></a></h2>
<?php if ( $show_date ) : ?>
<time datetime="<?php echo esc_attr( get_the_date( 'c' ) ); ?>"><?php echo esc_html( get_the_date() ); ?></time>
<?php endif; ?>
</article>
投稿タイプが news なら parts/card-news.php、無ければ parts/card.php が使われます。
定義ファイルは require で読む
// functions.php
require get_theme_file_path( 'inc/setup.php' );
require get_theme_file_path( 'inc/template-functions.php' );
get_theme_file_path() は子テーマにファイルがあれば子テーマ、無ければ親テーマのパスを返すので、パスの直書きより安全です(get_theme_file_path() の使い方|説明・引数・注意点)。
動作確認(検証環境と結果)
WordPress 7.1.2(ja)、PHP 8.2.12 の CLI 検証環境で、親テーマ wl1-parent(parts/card.php と parts/card-news.php)と、parts/card-news.php だけを持つ子テーマ wl1-child を作って有効化し、確認しました。
get_template_part( 'parts/card', 'news' )→ 子テーマのcard-news.phpが読み込まれた。get_template_part( 'parts/card', 'event', array( 'title' => 'イベント' ) )→card-event.phpが無いので親テーマのcard.phpが読み込まれ、$args['title']はイベント。呼び出し元で定義した変数$localは見えなかった。- 同じパーツを2回呼ぶと、2回とも出力された(ループ内で使える)。
- 存在しないパーツ
parts/noneの戻り値はfalseで、エラーは出なかった。 include get_template_directory() . '/parts/card-news.php'は、子テーマにファイルがあっても親テーマの内容を出力した。includeしたcard.phpでは$localが見えた。locate_template()は/themes/wl1-child/parts/card-news.phpを返した。get_template_part_parts/cardアクションは、読み込みの直前に$name = 'news'で実行された。- 手順の parts/card を parts/card-post.php(投稿タイプ
post用)として置き、ループで $args に show_date => true を渡すと、
と - get_template_part( ‘parts/card.php’ ) のように拡張子まで書くと、戻り値は alse で何も読み込まれなかった。
- get_theme_file_path() は、子テーマにある parts/card-news.php では子テーマのパス、親テーマにしかない inc-setup.php では親テーマのパスを返した。
- ob_start() / ob_get_clean() で囲むと、パーツの出力を文字列 ‘[child card-news]’ として受け取れた。
- 確認後、Twenty Twenty-Five に戻してテーマを削除した。
ログは testsget-template-part-vs-include-difference.md にあります。
get_template_part と includeの違いの注意点
get_template_part()はファイルが無くても黙ってfalseを返すので、ファイル名の誤字に気づきにくいです。開発中は戻り値を確認すると早く見つかります。$argsを使えるのは WordPress 5.5.0 以降です。locate_template()に利用者の入力をそのまま渡さないでください。リファレンスのユーザーノートでも、ディレクトリトラバーサルを防がない点が指摘されています。get_template_part()の slug・name も同様に、固定値か許可リストから選びます。- ヘッダー・フッター・サイドバーは、専用の
get_header()・get_footer()・get_sidebar()を使います。
get_template_part と includeの違いでよくあるミス
- テンプレートパーツを
includeで読み、子テーマで上書きできない。 - 呼び出し元の変数がパーツ内で使えると思い込み、未定義の警告を出す(
$argsで渡す)。 get_template_part( 'parts/card.php' )のように拡張子まで書き、card.php.phpを探してしまう。- 関数定義ファイルを
get_template_part()で読み、子テーマで同名ファイルを置いたときに二重定義になる。
get_template_part と includeの違いのチェックリスト
- [ ] 表示部品は
get_template_part()、定義ファイルはrequireにした - [ ] slug に拡張子を付けていない
- [ ] パーツへの値は
$argsで渡している - [ ] slug・name に利用者の入力を使っていない
- [ ] パスは
get_theme_file_path()で組み立てた
get_template_part と includeの違いのFAQ(よくある質問)
Q. get_template_part() で読み込んだファイルの中で $post は使えますか?
A. ループ内なら the_title() などのテンプレートタグがそのまま使えます。テンプレートタグはグローバルの投稿データを参照するためです。
Q. 戻り値で HTML を受け取りたい
A. get_template_part() は出力する関数です。文字列で欲しいときは ob_start() と ob_get_clean() で囲みます。
Q. ブロックテーマでは?
A. ブロックテーマでは parts/ フォルダの HTML テンプレートパーツをサイトエディターで使うのが基本です。PHP のパーツはパターンファイルなどで使います。
筆者の見解(get_template_part と includeの違い)
include は PHP の基本なので手が伸びがちですが、テーマの表示部品については get_template_part() を選ぶ方が、子テーマや将来の改修に強いと考えます。特に「呼び出し元の変数が見えない」という制約は不便に見えて、実際にはパーツが何に依存しているかを $args で明示させる良い制約だと私は思います。反対に、関数定義まで get_template_part() で読むのは二重定義の原因になるので、表示と定義で読み込み方を分けるのがおすすめです。
get_template_part と includeの違いの関連項目
- get_template_part() の使い方|説明・引数・注意点
- locate_template() の使い方|説明・引数・注意点
- load_template() の使い方|説明・引数・注意点
- get_theme_file_path() の使い方|説明・引数・注意点
- get_header() の使い方|説明・引数・注意点
- get_footer() の使い方|説明・引数・注意点
- get_sidebar() の使い方|説明・引数・注意点
- get_template_directory_uri と get_stylesheet_directory_uri の違い|子テーマでの使い分け
- WordPress テーマ自作の手順|最小構成(style.css・index.php)から作る方法

