get_template_part と include(require)の違い|WordPress テーマで PHP ファイルを読み込む方法の使い分け

結論

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の違いの関連項目

出典(一次情報)

タイトルとURLをコピーしました