WordPressのテーマ開発でよく使う「条件分岐タグ」ですが、意外と落とし穴が多いです。

筆者もつい最近まで勘違いしていたのですが、

is_single() は通常の投稿(post)専用だと思っていた

実は違います。is_single()カスタム投稿タイプにも true を返します

この記事では「投稿ページ・カスタム投稿・固定ページ・その他」に正確に分けるための書き方を、コピペで使えるテンプレートつきで解説します。


よくある誤解:is_single() はカスタム投稿も対象

まず最初に確認しておきたい重要なポイントです。

// ❌ よくある誤解:is_single() は通常投稿だけに反応する
<?php if (is_single()) : ?>
  <!-- 通常投稿のつもりが、カスタム投稿でも true になる -->

WordPressの公式ドキュメントによると、is_single()固定ページと添付ファイル以外の、主要な投稿タイプの個別ページで true を返します。

条件分岐タグ通常投稿カスタム投稿固定ページ
is_single()
is_page()
is_singular()

これを知らずにテンプレートやCSS分岐を書いていると、意図しない挙動が起きます。


基本の分類と正しい書き方

テーマ開発でよくある分類の正しい条件分岐はこう書きます。

<?php if (is_single() && get_post_type() === 'post') : ?>
  <!-- 1. 通常投稿ページ(post)のみ -->

<?php elseif (is_singular() && get_post_type() !== 'post' && !is_page()) : ?>
  <!-- 2. カスタム投稿のみ(通常投稿・固定ページを除く) -->

<?php elseif (is_singular() && !is_page()) : ?>
 <!-- 1&2. 通常投稿&カスタム投稿(固定ページを除く) -->

<?php elseif (is_page()) : ?>
  <!-- 3. 固定ページのみ -->

<?php else : ?>
  <!-- 4. その他(アーカイブ・カテゴリー・タグ・検索結果など) -->

<?php endif; ?>

なぜ get_post_type() が必要なのか

is_single() だけでは通常投稿とカスタム投稿を区別できないため、get_post_type() と組み合わせて投稿タイプ名で絞ります。

// 通常投稿のみ
is_single() && get_post_type() === 'post'

// 特定のカスタム投稿タイプのみ
is_singular() && get_post_type() === 'bulletin'

// カスタム投稿全般(通常投稿・固定ページを除く)
is_singular() && get_post_type() !== 'post' && !is_page()

よく使う条件分岐パターン集

カテゴリー別で分岐する

<?php if (is_single() && in_category('news')) : ?>
  <!-- カテゴリー「news」の投稿ページ -->

<?php elseif (is_single() && in_category('column')) : ?>
  <!-- カテゴリー「column」の投稿ページ -->

<?php endif; ?>

スラッグの代わりにカテゴリーIDも使えます。

<?php if (is_single() && in_category(5)) : ?>

投稿タイプ別で分岐する

<?php if (is_singular('bulletin')) : ?>
  <!-- カスタム投稿「bulletin」のみ -->

<?php elseif (is_singular('news')) : ?>
  <!-- カスタム投稿「news」のみ -->

<?php endif; ?>

is_singular('post_type_name')is_singular() && get_post_type() === 'post_type_name' の短縮形です。

テンプレートファイル別で分岐する

固定ページでカスタムテンプレートを使っている場合の分岐です。

<?php if (is_page_template('page-contact.php')) : ?>
  <!-- コンタクトページ専用のCSS・JSを読み込む -->
  <link rel="stylesheet" href="fm-contact.css">

<?php elseif (is_page_template('page-about.php')) : ?>
  <!-- 会社概要ページ -->

<?php endif; ?>

⚠️ is_page_template()固定ページ専用です。カスタム投稿では使えません。

スラッグ別で分岐する

<?php if (is_page('privacy-policy')) : ?>
  <!-- スラッグ「privacy-policy」の固定ページ -->

<?php endif; ?>

IDでも指定できます(ただしサイトをまたいで使い回す場合はIDが変わるためスラッグ推奨)。

<?php if (is_page(42)) : ?>

アーカイブ・一覧ページで分岐する

<?php if (is_post_type_archive('bulletin')) : ?>
  <!-- カスタム投稿「bulletin」のアーカイブ -->

<?php elseif (is_category()) : ?>
  <!-- カテゴリーアーカイブ -->

<?php elseif (is_tag()) : ?>
  <!-- タグアーカイブ -->

<?php elseif (is_tax()) : ?>
  <!-- カスタムタクソノミーアーカイブ -->

<?php elseif (is_search()) : ?>
  <!-- 検索結果ページ -->

<?php endif; ?>

コピペで使えるテンプレート

テンプレート①:CSS分岐(head.phpなど)

ページ種別ごとにCSSを読み分けたいときに使えます。

<?php if (is_404()) : ?>
  <!-- 404ページ(最優先) -->
  <link rel="stylesheet" href="ly-404.css">

<?php elseif (is_single() && get_post_type() === 'post') : ?>
  <!-- 通常投稿ページ -->
  <link rel="stylesheet" href="ly-single.css">

<?php elseif (is_singular('bulletin')) : ?>
  <!-- カスタム投稿「bulletin」 -->
  <link rel="stylesheet" href="ly-bulletin.css">

<?php elseif (is_singular() && !is_page() && get_post_type() !== 'post') : ?>
  <!-- その他のカスタム投稿 -->
  <link rel="stylesheet" href="ly-singular.css">

<?php elseif (is_front_page() || is_home() || is_page()) : ?>
  <!-- 固定ページ系 -->
  <link rel="stylesheet" href="ly-page.css">

  <?php if (is_page_template('page-contact.php')) : ?>
    <!-- コンタクトページ追加CSS -->
    <link rel="stylesheet" href="pg-contact.css">
  <?php endif; ?>

<?php else : ?>
  <!-- アーカイブ・カテゴリー・タグ・検索結果 -->
  <link rel="stylesheet" href="ly-archive.css">

<?php endif; ?>

テンプレート②:body IDにスラッグを割り当て

CSSのセレクタ #page-slug でページ別スタイルを当てるためによく使うパターンです。

<?php
$body_id = '';
global $post;

if (is_404()) {
  $body_id = 'error-404';

} elseif (is_front_page()) {
  $body_id = 'front';

} elseif (is_home()) {
  $body_id = 'home';

} elseif (is_singular()) {
  if ($post && isset($post->post_name)) {
    $body_id = esc_attr($post->post_name);
  }

} elseif (is_post_type_archive()) {
  $body_id = 'archive-' . esc_attr(get_post_type());

} elseif (is_category() || is_tag() || is_tax()) {
  $term = get_queried_object();
  if ($term && isset($term->slug)) {
    $body_id = 'archive-' . esc_attr($term->slug);
  }

} elseif (is_search()) {
  $body_id = 'search-results';

} else {
  $body_id = 'default';
}
?>
<body id="<?php echo $body_id; ?>" <?php body_class(); ?>>

テンプレート③:テンプレートファイルの分岐(functions.php)

カスタム投稿に singular.php を使いたいとき、template_include フィルターで制御します。

// functions.php
function my_custom_template_include($template) {
  if (get_post_type() === 'post' && is_single()) {
    // 通常投稿 → single.php
    $new_template = locate_template(['single.php']);
    if ($new_template) return $new_template;

  } elseif (is_singular() && !is_page() && get_post_type() !== 'post') {
    // カスタム投稿 → singular.php
    $new_template = locate_template(['singular.php']);
    if ($new_template) return $new_template;
  }

  return $template;
}
add_filter('template_include', 'my_custom_template_include');

singular.php 内でさらに投稿タイプ別に分岐することもできます。

// singular.php
<?php if (get_post_type() === 'bulletin') : ?>
  <?php get_template_part('parts/content', 'bulletin'); ?>

<?php elseif (get_post_type() === 'news') : ?>
  <?php get_template_part('parts/content', 'news'); ?>

<?php endif; ?>

テンプレート階層と条件分岐の関係まとめ

WordPressがどのテンプレートファイルを読み込むかはテンプレート階層で決まります。条件分岐タグはそのファイル内での処理分岐に使います。

テンプレートファイル(WordPress が自動選択)
└─ 個別表示
    ├─ single-{post_type}.php  ← カスタム投稿専用を作るならここ
    ├─ single.php              ← 通常投稿&カスタム投稿の共通
    ├─ singular.php            ← 上記がない場合のフォールバック
    └─ index.php

└─ 固定ページ
    ├─ カスタムテンプレート.php
    ├─ page-{slug}.php
    ├─ page.php
    └─ singular.php

└─ アーカイブ
    ├─ archive-{post_type}.php
    ├─ category.php / tag.php
    ├─ archive.php
    └─ index.php               ← search.php はここにフォールバック(archive.php ではない)

注意点search.phparchive.php にフォールバックしません。search.phpindex.php の順です。検索結果ページのレイアウトはカテゴリーページと似ていても、テンプレートは独立して作る必要があります。


まとめ

やりたいこと正しい書き方
通常投稿のみis_single() && get_post_type() === 'post'
カスタム投稿のみis_singular() && !is_page() && get_post_type() !== 'post'
特定のカスタム投稿のみis_singular('post_type_name')
固定ページのみis_page()
特定の固定ページis_page('slug')
カスタムテンプレートis_page_template('template.php') ※固定ページのみ
404ページis_404() を最優先で書く

is_single() がカスタム投稿にも反応するという仕様を知っているだけで、テーマ開発の多くの「なぜか動かない」を防げます。ぜひこの記事のテンプレートをベースにカスタマイズしてみてください。