カスタムページテンプレートでis_page()が効かない理由と対処法【WordPress】

WordPress

こんにちは!コーダーのゆうしです。

WordPressでカスタムページテンプレートを作って、header.php や functions.php に is_page() で条件分岐を書いたのに「なぜか効かない」という経験はありませんか?

これにはちゃんとした理由があります。今回は is_page() がカスタムページテンプレートで効かない原因と、正しい対処法を解説します。

そもそもカスタムページテンプレートとは

WordPressのカスタムページテンプレートとは、固定ページや投稿に対して通常のテンプレートとは別のレイアウト・デザインを適用できる仕組みです。PHPファイルの先頭に以下のようなコメントを書くだけでWordPressがテンプレートとして認識します。

/* Template Name: 会社概要ページ用 */

管理画面の固定ページ編集画面にある「テンプレート」プルダウンから選択することで、そのページにだけ別のテンプレートが当たるようになります。

is_page()がループ内で効かない理由

WordPressのループ(while ( have_posts() ) : the_post();)の中では、the_post() を呼び出すたびにグローバル変数 $post が現在処理中の投稿オブジェクトで上書きされます。

is_page() はこの $post の状態に依存しているため、ループの中では正しく動作しません。これはWordPressの公式Codexにも「ループの中では is_page() は機能しません」と明記されています。

 NG 

// ループの中でis_page()を使っている
while ( have_posts() ) : the_post();

  if ( is_page( 'company' ) ) {
    // ← ループ内では正しく動作しない
    get_template_part( 'parts/company-header' );
  }

endwhile;

同じ理由で、is_page_template() もループ内では動作しません。

正しい対処法:is_page_template()を使う

カスタムページテンプレートを使っているかどうかを判定するなら、is_page_template() を使うのが正解です。引数にテンプレートファイル名(テーマフォルダからの相対パス)を渡すと、そのテンプレートが使われているページで true を返します。

ループの外(have_posts() の前)や header.phpfunctions.php のフック内で使うのが正しいタイミングです。

 OK 

// ループの外で使う
if ( is_page_template( 'page-company.php' ) ) {
  // page-company.php テンプレートが使われているページ
  get_template_part( 'parts/company-header' );
}

引数に指定するのはテーマフォルダからの相対パスです。サブディレクトリに置いている場合はパスを含めて書きます。

// テンプレートをサブディレクトリに置いている場合
if ( is_page_template( 'page-templates/page-company.php' ) ) {
  // 処理
}

is_page()とis_page_template()の違い

関数何を判定するか主な用途
is_page()特定の固定ページ(IDやスラッグ)を表示しているか特定ページだけ処理を変えたい
is_page_template()特定のカスタムテンプレートが使われているかテンプレート単位で処理を変えたい

カスタムページテンプレートに関する条件分岐は、ページIDやスラッグではなく「テンプレートが何か」で判断できる is_page_template() のほうが管理しやすくておすすめです。ページを複製したり別のページに同じテンプレートを当てたりしたときも条件分岐を書き直す必要がありません。

カスタム投稿タイプでも使いたい場合はTemplate Post Typeを追加する

デフォルトでは、カスタムページテンプレートは固定ページ(page)にしか表示されません。通常の投稿やカスタム投稿タイプの編集画面にもテンプレートを表示したい場合は、ファイル先頭のコメントに Template Post Type を追加します。

/*
 * Template Name: 会社概要ページ用
 * Template Post Type: post, page, news
 */

Template Post Type に投稿タイプのスラッグをカンマ区切りで指定します。上の例では通常投稿(post)・固定ページ(page)・カスタム投稿「news」の編集画面にこのテンプレートが選択肢として表示されます。

💡 Template Post Type を書かない場合は自動的に page が適用されます。固定ページ専用のテンプレートであれば省略してかまいません。

躓きやすいポイント

テンプレートファイルが管理画面に表示されない

テンプレートを作ったのに管理画面のプルダウンに出てこない場合は以下を確認してみてください。

  • ファイル先頭の Template Name: のスペルが合っているか
  • テーマのルートディレクトリか page-templates/ などの認識されるディレクトリに置いているか
  • ファイルの文字コードが UTF-8 になっているか(テンプレート名を日本語にした場合)

is_page_template()の引数のパスが合っていない

 NG 

// テーマフォルダからのパスが違う
is_page_template( 'page-company.php' );
// → 実際は page-templates/ 以下に置いている場合は true にならない

 OK 

// テーマフォルダからの正しい相対パスで指定する
is_page_template( 'page-templates/page-company.php' );

引数なしで is_page_template() を呼び出すと、何かしらのカスタムテンプレートが使われていれば true を返します。特定のテンプレートを限定したい場合はファイルパスを正確に渡してください。

ループの後で使う場合はwp_reset_query()が必要なことがある

ループが終わった直後に is_page_template() を使いたい場合、グローバル変数が書き換わったままになっていることがあります。その場合は wp_reset_query() を呼び出してリセットしてから使ってください。

endwhile;

wp_reset_query(); // グローバル変数をリセット

if ( is_page_template( 'page-templates/page-company.php' ) ) {
  // ここで使えるようになる
}

⚠️ wp_reset_query() はメインクエリ全体をリセットするため、サブループ(WP_Query)の後であれば wp_reset_postdata() を使うのが正しい場面もあります。使い分けはこちらの記事も参考にしてみてください。

まとめ

カスタムページテンプレートで is_page() が効かない原因は、ループ内でグローバル変数 $post が書き換えられることにあります。テンプレート単位で条件分岐したい場合は is_page_template() をループの外で使うのが正しい方法です。

  • ループ内では is_page() も is_page_template() も動作しない
  • カスタムテンプレートの判定は is_page_template() をループの外で使う
  • カスタム投稿にも使いたい場合は Template Post Type を追加する

ご不明な点やコーディングのご依頼はお問い合わせからお気軽にどうぞ。

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