Code Explain

Geminiの鋭い視点と分かりやすい解説で、プログラミングスキルを向上させましょう!

WordPress single.phpの達人になろう!条件分岐を駆使して記事ページを自在にカスタマイズする方法(徹底解説)

WordPressでウェブサイトを構築・運用されている皆さん、こんにちは!プロのブロガーであり、日々WordPressと格闘している私です。

今回は、WordPressサイトの表現力を飛躍的に向上させる「single.php における条件分岐」について、その基礎から応用、そしてプロが実践するベストプラクティスまで、徹底的に深掘りしていきます。

「特定の記事だけデザインを変えたい」「カスタム投稿タイプごとにレイアウトを分けたい」「カテゴリーによって表示する情報を変えたい」――そんな願い、実は single.php の条件分岐を使えば、驚くほど簡単に実現できるんです。

この記事を読めば、あなたは単なるWordPressユーザーから一歩踏み出し、サイトの「顔」とも言える記事ページを自在に操る「single.php の達人」になることでしょう。

さあ、あなたのWordPressサイトの可能性を最大限に引き出す旅に出かけましょう!


目次

  1. single.php とは?WordPressテンプレート階層における重要性
  2. なぜ single.php で条件分岐が必要なのか?具体的なユースケース
  3. WordPressで使える主要な条件分岐タグを徹底解説
    • 投稿タイプによる分岐: is_singular()get_post_type()
    • カテゴリーによる分岐: in_category()has_term()
    • タグによる分岐: has_tag()
    • 投稿IDによる分岐: is_single()get_the_ID()
    • スラッグによる分岐: is_single()
    • 投稿者による分岐: get_the_author_ID()
    • カスタムフィールドによる分岐: get_post_meta() / get_field()
    • その他の便利な条件分岐: is_user_logged_in(), has_post_thumbnail() など
  4. single.php をスマートに!効率的な実装テクニック
    • get_template_part() を利用したモジュール化
    • カスタムテンプレートファイル single-{post-type}.php を活用する
    • 条件分岐のネストと優先順位の考え方
  5. プロが実践!よくある落とし穴とベストプラクティス
    • 可読性・保守性の高いコードを書く
    • パフォーマンスへの配慮
    • 子テーマの利用とテーマアップデート戦略
    • セキュリティ意識を持った実装
  6. 実践!コピペで使えるコード例と詳細解説
    • 例1: カスタム投稿タイプ「イベント」と「ニュース」でレイアウトを切り替える
    • 例2: 特定のカテゴリー「キャンペーン」の記事に特別なバナーを表示する
    • 例3: カスタムフィールドの値によって表示コンテンツを出し分ける
    • 例4: 特定の投稿ID、またはスラッグの記事にのみ独自の要素を表示する
  7. まとめ:single.php 分岐をマスターして、あなたのサイトを次のレベルへ

1. single.php とは?WordPressテンプレート階層における重要性

まず、single.php がどのような役割を持つファイルなのか、改めて確認しておきましょう。

WordPressは、アクセスされたURLに応じて表示すべきコンテンツを判断し、適切なテンプレートファイルを探してページを生成します。これを「テンプレート階層」と呼びます。

テンプレート階層における single.php の位置づけ

簡単に言えば、single.php は個別の投稿(ブログ記事、固定ページを除くカスタム投稿タイプなど)を表示するためのテンプレートファイルです。

もう少し詳しく見てみましょう。

  • 単一投稿が表示される際の優先順位(一部抜粋):
    1. single-{post-type}-{slug}.php (例: single-product-awesome-item.php)
    2. single-{post-type}.php (例: single-product.php)
    3. single-{id}.php (例: single-123.php)
    4. single.php ← 今回の主役!
    5. singular.php (単一ページ全般のフォールバック)
    6. index.php (最終的なフォールバック)

このように、特定の投稿タイプやスラッグ、IDに特化したファイルが存在しない場合、最終的に「single.php」が参照される、非常に汎用性の高いファイルです。ほとんどのWordPressテーマにおいて、ブログ記事の表示はこの single.php が担っています。

single.php の基本的な構造

一般的な single.php は、以下のような構造を持っています。

<?php get_header(); ?>

<main id="primary" class="site-main">

    <?php
    while ( have_posts() ) :
        the_post(); // 投稿データをセット

        // ここに記事のコンテンツが表示される

        // 例: 記事タイトル
        the_title( '<h1 class="entry-title">', '</h1>' );

        // 例: 記事本文
        the_content();

        // 例: 記事のメタ情報(投稿日、カテゴリなど)
        // wp_link_pages( array(...) ); // ページ送りがある場合

        // 例: コメントテンプレートの読み込み
        if ( comments_open() || get_comments_number() ) :
            comments_template();
        endif;

        // 前後の記事へのリンク
        the_post_navigation();

    endwhile; // End of the loop.
    ?>

</main><!-- #main -->

<?php get_sidebar(); // サイドバーがあれば読み込む ?>
<?php get_footer(); // フッターを読み込む ?>

この the_post(); の後に続く部分が、記事のタイトル、本文、メタ情報などを表示するための肝となる部分です。そして、この部分に条件分岐を記述することで、記事ごとに表示を変化させることが可能になります。

2. なぜ single.php で条件分岐が必要なのか?具体的なユースケース

「すべての記事が同じレイアウトで何がいけないの?」そう思われた方もいるかもしれません。しかし、ウェブサイトを運用していると、単一のレイアウトでは対応しきれない状況が頻繁に発生します。

ここでは、single.php で条件分岐が求められる具体的なユースケースをいくつかご紹介します。

ユースケース1: カスタム投稿タイプごとのデザイン変更

あなたは商品紹介サイトを運営しており、「ブログ記事」とは別に「商品レビュー」というカスタム投稿タイプを作成したとします。

  • ブログ記事: 投稿者情報、公開日、カテゴリ、タグなどを強調したい。
  • 商品レビュー: 商品の評価、価格、購入ボタン、関連商品リストなどを表示したい。

このように、投稿タイプが異なれば、表示すべき情報やデザインの優先順位も大きく変わってきます。single.php の分岐を使えば、それぞれの投稿タイプに最適なレイアウトを適用できます。

ユースケース2: 特定のカテゴリー・タグに属する記事に特別な要素を追加

特定のカテゴリー(例: 「キャンペーン情報」「特集記事」)に属する記事に、目立つバナーや特別なCTA(Call To Action)ボタンを表示したい場合があります。

  • キャンペーン情報」カテゴリの記事に、期間を限定した告知バナーを自動的に表示。
  • 初心者向け」タグが付いた記事に、「まずはこちらを読もう!」といった導入メッセージを表示。

このような場合は、カテゴリーやタグを条件に分岐させることで、手動で毎回追加する手間を省き、かつ統一されたデザインで情報を発信できます。

ユースケース3: 個別の記事に固有のレイアウトや機能を持たせる

「この特定の記事だけは、サイドバーを非表示にして、コンテンツを全幅で表示したい」「あの記事にだけ、特別なアンケートフォームを埋め込みたい」といった要望もあるでしょう。

これは、記事IDやスラッグを条件にして分岐することで実現できます。汎用的な single.php の中に、特定の記事にだけ適用される特別な処理を組み込むことが可能です。

ユースケース4: ユーザーのログイン状態や権限によって表示を変える

会員制サイトの場合、ログインしているユーザーにだけ表示する情報や、特定の権限を持つユーザーにだけ表示する管理ツールのようなものが必要になることがあります。

  • ログインユーザーには「お気に入りに追加」ボタンを表示。
  • 投稿者以上の権限を持つユーザーには「記事の編集」ボタンを表示。

このように、ユーザーの状態に応じた表示の出し分けも、single.php の条件分岐で対応できます。

ユースケース5: カスタムフィールドの値に応じた動的な表示

Advanced Custom Fields (ACF) などのプラグインでカスタムフィールドを多様している場合、そのフィールドの値に基づいてコンテンツの表示を変えたいケースがあります。

  • ギャラリー表示」というカスタムフィールドが true の場合、投稿本文の上に画像スライダーを表示。
  • ビデオURL」というカスタムフィールドが入力されている場合、そのURLのビデオを埋め込み表示。

カスタムフィールドの値は、まさに「動的な情報」の宝庫です。これを活用しない手はありません。


これらのユースケースからもわかるように、single.php の条件分岐は、サイトの表現力を豊かにし、ユーザーエクスペリエンスを向上させるための強力なツールなのです。

3. WordPressで使える主要な条件分岐タグを徹底解説

それでは、具体的にどのような条件分岐タグを使って single.php をカスタマイズしていくのかを見ていきましょう。それぞれのタグについて、用途、使い方、具体的なコード例を詳しく解説します。

3.1. 投稿タイプによる分岐: is_singular()get_post_type()

最も基本的な条件分岐の一つが、投稿タイプによるものです。WordPressの投稿タイプには、「投稿 (post)」「固定ページ (page)」の他に、開発者が自由に定義できる「カスタム投稿タイプ」があります。

is_singular( string|array $post_type = '' )

現在表示しているのが単一ページ(single page, ページングを除く)であり、かつ指定された投稿タイプであるかどうかを判定します。引数を指定しない場合は、任意の投稿タイプの単一ページで true を返します。

  • 用途: 特定の投稿タイプ(または複数の投稿タイプ)の単一ページにのみ適用したいデザインやコンテンツがある場合。
  • 使い方: if ( is_singular( 'post_type_slug' ) )

コード例: 「ニュース」というカスタム投稿タイプと「ブログ記事」で表示を切り替える

<?php
if ( is_singular( 'news' ) ) {
    // ニュース記事の場合の処理
    echo '<div class="news-template">';
    the_title( '<h1 class="news-title">', '</h1>' );
    the_content();
    echo '<p class="news-date">公開日: ' . get_the_date() . '</p>';
    echo '</div>';
} elseif ( is_singular( 'post' ) ) { // デフォルトの「投稿」の場合
    // ブログ記事の場合の処理
    echo '<div class="blog-template">';
    the_title( '<h1 class="blog-title">', '</h1>' );
    the_content();
    echo '<p class="blog-meta">カテゴリー: ' . get_the_category_list( ', ' ) . '</p>';
    echo '</div>';
} else {
    // それ以外の投稿タイプの場合のデフォルト処理
    the_title( '<h1>', '</h1>' );
    the_content();
}
?>

is_singular() は複数の投稿タイプを配列で指定することも可能です。 例: if ( is_singular( array( 'post', 'news', 'event' ) ) )

get_post_type( WP_Post|int|null $post = null )

現在ループ中の投稿の投稿タイプスラッグを取得します。is_singular() とは異なり、直接「投稿タイプ名」を取得して、その値で条件分岐を行うことができます。

  • 用途: 投稿タイプ名を取得し、その文字列を直接比較したい場合や、取得した投稿タイプ名を使って動的にファイル名を生成したい場合など。
  • 使い方: if ( 'post_type_slug' === get_post_type() )

コード例: get_template_part() と組み合わせて動的にテンプレートを読み込む

<?php
// 現在の投稿タイプ名を取得
$post_type = get_post_type();

// 取得した投稿タイプ名に基づいて、特定のテンプレートパーツを読み込む
// 例: 'content-post.php', 'content-news.php', 'content-event.php' など
get_template_part( 'template-parts/content', $post_type );

// もし 'template-parts/content-news.php' が存在しない場合は、
// 'template-parts/content.php' が読み込まれる
?>

これは非常に強力なテクニックで、後述の「get_template_part() を利用したモジュール化」でさらに詳しく解説します。

3.2. カテゴリーによる分岐: in_category()has_term()

投稿が特定のカテゴリーに属しているかどうかで表示を分けたい場合に利用します。

in_category( int|string|array $category, WP_Post|int|null $_post = null )

現在ループ中の投稿が、指定されたカテゴリーに属しているかを判定します。カテゴリーはID、スラッグ、またはカテゴリー名で指定できます。複数のカテゴリーを配列で指定することも可能です。

  • 用途: 特定のカテゴリー記事にバナーを表示したり、レイアウトを変更したりする場合。
  • 使い方: if ( in_category( 'category_slug' ) ) または if ( in_category( 123 ) )

コード例: 「重要なお知らせ」カテゴリーの記事にのみ、注意書きを表示

<?php
the_title( '<h1>', '</h1>' );

if ( in_category( 'important-notice' ) ) {
    // 「重要なお知らせ」カテゴリーの場合のみ表示
    echo '<div class="alert alert-warning">';
    echo '<h3>【重要】必ずお読みください</h3>';
    echo '<p>この記事は、サイトの重要な変更点や告知を含んでいます。</p>';
    echo '</div>';
}

the_content();
?>

has_term( int|string|array $term, string|array $taxonomy = 'post_tag', WP_Post|int|null $post = null )

任意の投稿が特定のタクソノミー(カテゴリー、タグ、カスタムタクソノミー)のターム(項目)に属しているかを判定します。in_category() は「カテゴリー」専用ですが、has_term() はより汎用的に使えます。

  • 用途: カスタムタクソノミーを含め、より広範囲な分類で条件分岐したい場合。
  • 使い方: if ( has_term( 'term_slug', 'taxonomy_slug' ) )

コード例: カスタムタクソノミー「ブランド」の「Nike」タームに属する商品記事に、特別なロゴを表示

<?php
the_title( '<h1>', '</h1>' );

if ( has_term( 'nike', 'brand' ) ) { // カスタムタクソノミー 'brand' の 'nike' ターム
    echo '<div class="brand-logo-nike">';
    echo '<img src="/wp-content/themes/your-theme/images/nike-logo.png" alt="Nike Logo">';
    echo '</div>';
}

the_content();
?>

3.3. タグによる分岐: has_tag()

カテゴリーと同様に、タグによっても条件分岐を行うことができます。

has_tag( int|string|array $tag = '', WP_Post|int|null $post = null )

現在ループ中の投稿が、指定されたタグに属しているかを判定します。タグはID、スラッグ、またはタグ名で指定できます。複数のタグを配列で指定することも可能です。

  • 用途: 特定のテーマやキーワードに関連する記事に特別な要素を追加したい場合。
  • 使い方: if ( has_tag( 'special-offer' ) )

コード例: 「限定セール」タグが付与された記事に、期間を示す情報を表示

<?php
the_title( '<h1>', '</h1>' );

if ( has_tag( 'limited-sale' ) ) {
    echo '<div class="sale-banner">';
    echo '<p class="text-danger">【本日限り!】このセールは間もなく終了します!</p>';
    echo '</div>';
}

the_content();
?>

3.4. 投稿IDによる分岐: is_single()get_the_ID()

個別の投稿、つまり特定の記事にだけ適用したいデザインや機能がある場合に利用します。

is_single( int|string|array $post = '' )

現在ループ中の投稿が、指定された投稿ID、スラッグ、またはタイトルと一致するかを判定します。

  • 用途: 特定の投稿(1つまたは複数)に限定したカスタマイズを行いたい場合。
  • 使い方: if ( is_single( 123 ) ) または if ( is_single( 'post-slug' ) )

コード例: IDが 5 の記事に特別なメッセージを表示

<?php
the_title( '<h1>', '</h1>' );

if ( is_single( 5 ) ) { // 投稿IDが5の場合
    echo '<p class="special-message">この投稿は特別な企画記事です。</p>';
}

the_content();
?>

配列で複数のIDを指定することも可能です: if ( is_single( array( 5, 10, 15 ) ) )

get_the_ID()

現在ループ中の投稿のIDを取得します。

  • 用途: 投稿IDを直接取得して、比較や他の関数への引数として利用したい場合。
  • 使い方: if ( 123 === get_the_ID() )

コード例: 投稿IDが10の記事の場合、記事下に関連商品へのリンクを表示

<?php
the_title( '<h1>', '</h1>' );
the_content();

if ( 10 === get_the_ID() ) {
    echo '<div class="related-products">';
    echo '<h3>この記事で紹介した関連商品</h3>';
    echo '<ul><li><a href="#">商品A</a></li><li><a href="#">商品B</a></li></ul>';
    echo '</div>';
}
?>

3.5. スラッグによる分岐: is_single() (再掲)

is_single() は投稿IDだけでなく、スラッグでも判定が可能です。

  • 用途: 投稿IDは管理画面で確認が必要ですが、スラッグはURLから判断しやすいため、特定の記事をスラッグで指定したい場合に便利です。
  • 使い方: if ( is_single( 'your-post-slug' ) )

コード例: スラッグが my-special-offer の記事に、特別なフッターを表示

<?php
the_title( '<h1>', '</h1>' );
the_content();

if ( is_single( 'my-special-offer' ) ) {
    echo '<div class="special-offer-footer">';
    echo '<p>この素晴らしいオファーは、今すぐチェック!</p>';
    echo '<a href="/contact/" class="btn btn-primary">お問い合わせはこちら</a>';
    echo '</div>';
}
?>

3.6. 投稿者による分岐: get_the_author_ID()

特定の投稿者(著者)が書いた記事にのみ特別な表示をしたい場合に利用します。

get_the_author_ID()

現在ループ中の投稿の著者IDを取得します。

  • 用途: 特定の著者の記事に、その著者のプロフィール情報を詳しく表示したり、独自のスタイルを適用したりする場合。
  • 使い方: if ( 1 === get_the_author_ID() ) (ID 1 は通常、最初の管理者アカウント)

コード例: 著者IDが1(サイト管理者)の記事に、特別な著者プロフィールを表示

<?php
the_title( '<h1>', '</h1>' );
the_content();

if ( 1 === get_the_author_ID() ) {
    echo '<div class="author-box author-admin">';
    echo '<h3>サイト管理者からのメッセージ</h3>';
    echo '<p>この記事は、サイトの運営責任者である私が執筆しました。</p>';
    // さらに詳しい情報を表示することも可能
    echo '</div>';
} else {
    // 他の著者の記事の場合は通常の著者情報を表示
    echo '<div class="author-box">';
    the_author_posts_link(); // 著者の記事一覧へのリンク
    echo '<p>' . get_the_author_meta( 'description' ) . '</p>';
    echo '</div>';
}
?>

3.7. カスタムフィールドによる分岐: get_post_meta() / get_field()

WordPressのカスタムフィールドは、投稿に追加情報を付与するための非常に強力な機能です。このカスタムフィールドの値に基づいて、表示を動的に変更することができます。

get_post_meta( int $post_id, string $key = '', bool $single = false )

指定された投稿のカスタムフィールドの値を取得します。$singletrue にすると、単一の値が返されます。

  • 用途: 特定のカスタムフィールドが設定されているか、または特定の値を持っているかによって、コンテンツの表示を切り替えたい場合。
  • 使い方: $value = get_post_meta( get_the_ID(), 'custom_field_key', true );

コード例: 「has_sidebar」というカスタムフィールドが false の記事でサイドバーを非表示にする(single.php の中で直接サイドバーの呼び出しを制御する場合)

<?php get_header(); ?>

<main id="primary" class="site-main">

    <?php
    while ( have_posts() ) :
        the_post();

        the_title( '<h1>', '</h1>' );
        the_content();

        // 'has_sidebar' カスタムフィールドの値を取得
        $has_sidebar = get_post_meta( get_the_ID(), 'has_sidebar', true );

        if ( 'false' === $has_sidebar ) {
            // サイドバーを非表示にしたい場合の特別な処理(例: CSSクラスを付与)
            echo '<style>.site-main { width: 100%; }</style>';
        }

    endwhile;
    ?>

</main>

<?php
// カスタムフィールドの値に基づいてサイドバーを表示するかどうかを分岐
if ( 'false' !== $has_sidebar ) { // 'has_sidebar' が 'false' でない場合
    get_sidebar();
}
?>
<?php get_footer(); ?>

get_field( string $field_name, int|WP_Post|null $post_id = null, bool $format_value = true ) (ACF利用時)

Advanced Custom Fields (ACF) プラグインを利用している場合、get_field() 関数を使うのが一般的で便利です。カスタムフィールドのタイプに応じて、整形された値が返されます。

  • 用途: ACFで作成したカスタムフィールドの値に基づいて、コンテンツを柔軟に表示したい場合。
  • 使い方: $value = get_field( 'your_acf_field_name' );

コード例: ACFで作成した「動画URL」カスタムフィールドに値がある場合、動画プレイヤーを表示

<?php
the_title( '<h1>', '</h1>' );
the_content();

// 'video_url' というACFフィールドの値を取得
$video_url = get_field( 'video_url' );

if ( $video_url ) { // 動画URLが設定されている場合
    echo '<div class="video-container">';
    echo '<iframe src="' . esc_url( $video_url ) . '" frameborder="0" allowfullscreen></iframe>';
    echo '</div>';
}
?>

3.8. その他の便利な条件分岐

single.php 内で活用できるその他の便利な条件分岐タグも紹介します。

is_user_logged_in()

現在閲覧しているユーザーがWordPressにログインしているかどうかを判定します。

  • 用途: ログインユーザーにのみ表示するコンテンツや、ログインしていないユーザーに登録を促すメッセージなどを表示する場合。
<?php
if ( is_user_logged_in() ) {
    echo '<p class="logged-in-message">ようこそ、' . wp_get_current_user()->display_name . 'さん!</p>';
    // 会員限定コンテンツなど
} else {
    echo '<p class="logged-out-message"><a href="' . wp_login_url() . '">ログイン</a>して会員限定コンテンツをチェック!</p>';
}
?>

current_user_can( string|array $capability )

現在ログインしているユーザーが指定された権限を持っているかどうかを判定します。

  • 用途: 管理者のみが編集できるボタンを表示するなど、ユーザー権限に応じた表示をしたい場合。
<?php
if ( current_user_can( 'edit_posts' ) ) {
    echo '<a href="' . get_edit_post_link() . '" class="edit-post-button">この記事を編集する</a>';
}
?>

has_post_thumbnail( WP_Post|int|null $post = null )

現在ループ中の投稿にアイキャッチ画像(サムネイル)が設定されているかどうかを判定します。

  • 用途: アイキャッチ画像がある場合とない場合で、レイアウトや代替テキストの表示を分けたい場合。
<?php
if ( has_post_thumbnail() ) {
    echo '<div class="post-thumbnail">';
    the_post_thumbnail( 'large' ); // 'large' サイズのアイキャッチ画像を表示
    echo '</div>';
} else {
    echo '<div class="no-thumbnail">';
    echo '<img src="' . get_template_directory_uri() . '/images/default-thumbnail.jpg" alt="No Thumbnail">';
    echo '</div>';
}
?>

これらの条件分岐タグを組み合わせることで、single.php の中で無限に近いカスタマイズが可能になります。しかし、コードが複雑になるため、次のセクションで紹介する「効率的な実装テクニック」を学ぶことが非常に重要です。

4. single.php をスマートに!効率的な実装テクニック

single.php の中に複雑な if/else if/else を書き続けると、コードが長くなり、可読性や保守性が低下してしまいます。そこで、プロが実践するスマートな実装テクニックを学びましょう。

4.1. get_template_part() を利用したモジュール化

WordPressには、テンプレートの一部をファイルとして分割し、必要に応じて読み込むための get_template_part() 関数があります。これを活用することで、single.php のコードを劇的に整理できます。

get_template_part( string $slug, string $name = null, array $args = array() )

指定されたスラッグ(ファイル名の前半部分)と名前(ファイル名の後半部分)を持つテンプレートパーツファイルを読み込みます。

  • 用途: 複雑な条件分岐の各ブロックを別ファイルに分割し、single.php をクリーンに保つ。
  • 仕組み: 例えば get_template_part( 'template-parts/content', 'news' ); と書くと、WordPressは以下の順序でファイルを探します。
    1. template-parts/content-news.php
    2. template-parts/content.php

この機能を使えば、投稿タイプごとに専用のコンテンツ表示部分を簡単に切り替えられます。

コード例: 投稿タイプごとに異なる content-*.php を読み込む

まず、single.php を以下のようにシンプルにします。

<?php get_header(); ?>

<main id="primary" class="site-main">

    <?php
    while ( have_posts() ) :
        the_post();

        // 現在の投稿タイプに応じて、content-{投稿タイプ}.php を読み込む
        // 例: 投稿タイプが 'post' なら 'content-post.php'
        // 投稿タイプが 'news' なら 'content-news.php'
        get_template_part( 'template-parts/content', get_post_type() );

        // 前後の記事へのリンク
        the_post_navigation();

        // コメントセクション
        if ( comments_open() || get_comments_number() ) :
            comments_template();
        endif;

    endwhile;
    ?>

</main>

<?php get_sidebar(); ?>
<?php get_footer(); ?>

次に、template-parts ディレクトリ(または任意のディレクトリ)の中に、以下のようなファイルを作成します。

  • template-parts/content-post.php (デフォルトの投稿用)
  • template-parts/content-news.php (カスタム投稿タイプ 'news' 用)
  • template-parts/content-event.php (カスタム投稿タイプ 'event' 用)

それぞれのファイルには、その投稿タイプに特化したHTML構造やWordPressループ内のテンプレートタグを記述します。

template-parts/content-post.php の例:

<article id="post-<?php the_ID(); ?>" <?php post_class(); ?>>
    <header class="entry-header">
        <?php the_title( '<h1 class="entry-title">', '</h1>' ); ?>
        <div class="entry-meta">
            <span>公開日: <?php echo get_the_date(); ?></span>
            <span>カテゴリー: <?php the_category(', '); ?></span>
        </div>
    </header>

    <div class="entry-content">
        <?php the_content(); ?>
        <?php
        wp_link_pages(
            array(
                'before' => '<div class="page-links">' . esc_html__( 'Pages:', 'your-text-domain' ),
                'after'  => '</div>',
            )
        );
        ?>
    </div>

    <footer class="entry-footer">
        <?php the_tags( '<span class="tag-links">タグ: ', ', ', '</span>' ); ?>
        <?php get_template_part( 'template-parts/author-bio' ); // 著者情報パーツを読み込む ?>
    </footer>
</article>

template-parts/content-news.php の例:

<article id="post-<?php the_ID(); ?>" <?php post_class( 'news-article' ); ?>>
    <header class="news-header">
        <span class="news-date"><?php echo get_the_date( 'Y.m.d' ); ?></span>
        <?php the_title( '<h2 class="news-title">', '</h2>' ); ?>
    </header>

    <div class="news-content">
        <?php if ( has_post_thumbnail() ) : ?>
            <div class="news-thumbnail">
                <?php the_post_thumbnail( 'medium' ); ?>
            </div>
        <?php endif; ?>
        <?php the_content(); ?>
    </div>

    <footer class="news-footer">
        <p>提供元: 〇〇プレス</p>
        <?php get_template_part( 'template-parts/share-buttons' ); // SNSシェアボタンパーツを読み込む ?>
    </footer>
</article>

このようにすることで、single.php はシンプルになり、各投稿タイプの具体的な表示ロジックはそれぞれのファイルに集約され、非常に見通しが良くなります。

4.2. カスタムテンプレートファイル single-{post-type}.php を活用する

WordPressのテンプレート階層は、実はsingle.php の前に、特定の投稿タイプやスラッグ、IDに特化したテンプレートファイルを優先的に読み込む仕組みを持っています。

  • single-{post-type}.php: 特定のカスタム投稿タイプ(例: event)の単一ページを表示したい場合、single-event.php というファイルを作成すると、single.php よりも優先して読み込まれます。
  • single-{slug}.php: 特定のスラッグを持つ投稿(例: my-special-offer)の単一ページに、single-my-special-offer.php というファイルを適用できます。
  • single-{ID}.php: 特定のIDを持つ投稿(例: ID 123)に、single-123.php というファイルを適用できます。

メリット

  • single.php 内に条件分岐を書く必要がない: テンプレートファイルそのものが条件分岐の役割を果たすため、single.php が非常にクリーンになります。
  • 管理が容易: 特定の投稿タイプや記事に特化したレイアウトが必要な場合、その専用ファイルを編集するだけで済みます。

デメリット

  • ファイル数が増える: 細かく分けすぎると、ファイル管理が煩雑になる可能性があります。
  • 汎用性の欠如: single-event.phpevent 投稿タイプにしか使えません。共通部分が多い場合は、重複コードが発生する可能性があります。

使い分けの考え方

  • 投稿タイプごとに大幅にレイアウトや表示コンテンツが異なる場合: single-{post-type}.php を作成するのが最も効率的です。例えば、ブログ、商品、イベントなど、完全に異なる情報構造を持つ場合に有効です。
  • 投稿タイプは同じだが、特定の記事だけ微調整したい場合: single.php 内で is_single() やカスタムフィールドによる分岐を行うか、get_template_part() で部分的に切り替えるのが良いでしょう。single-{slug}.phpsingle-{ID}.php は、本当に「その記事だけ」という限定的な場合に検討します。
  • 共通部分が多いが一部だけ変更したい場合: single.php を基本とし、get_template_part() で切り替える部分を増やすのがおすすめです。

4.3. 条件分岐のネストと優先順位の考え方

条件分岐を組み合わせる場合、ネスト(入れ子)の深さや優先順位を考慮することが重要です。

if ( is_singular( 'event' ) ) {
    // イベント投稿の処理
    if ( has_tag( 'featured' ) ) {
        // 注目のイベントの処理
    } else {
        // 通常のイベントの処理
    }
} elseif ( is_singular( 'post' ) ) {
    // 通常投稿の処理
    if ( in_category( 'promotion' ) ) {
        // プロモーション記事の処理
    } else {
        // 通常のブログ記事の処理
    }
} else {
    // それ以外の投稿タイプの処理
}
  • ネストの推奨レベル: あまり深くネストしすぎると可読性が低下します。せいぜい2~3階層に留めるのが望ましいです。
  • 優先順位: 一般的に、より「具体的」な条件から先に判定するようにします。
    • 例: 特定の投稿ID > 特定のスラッグ > 特定の投稿タイプ > 特定のカテゴリー/タグ > デフォルト
  • 早期リターン: 可能であれば、条件が満たされたらすぐに処理を終えてしまう「早期リターン」の手法も有効です。
// 例: 特定の投稿ID 10 は完全に独自の表示
if ( 10 === get_the_ID() ) {
    get_template_part( 'template-parts/single', 'custom-10' );
    return; // 以降の処理は不要
}

// 次にカスタム投稿タイプによる分岐
if ( is_singular( 'event' ) ) {
    get_template_part( 'template-parts/content', 'event' );
} elseif ( is_singular( 'news' ) ) {
    get_template_part( 'template-parts/content', 'news' );
} else {
    get_template_part( 'template-parts/content', 'post' );
}

このように、最も優先度の高い例外的な条件を最初に処理することで、コードが読みやすくなり、意図しない挙動を防ぐことができます。

5. プロが実践!よくある落とし穴とベストプラクティス

single.php での条件分岐は強力ですが、誤った使い方をするとサイトのパフォーマンス低下、保守性の悪化、さらにはセキュリティリスクにもつながります。プロとして意識すべきベストプラクティスを見ていきましょう。

5.1. 可読性・保守性の高いコードを書く

  • コメントを適切に残す: なぜその条件分岐が必要なのか、何を実現しようとしているのかを簡潔に記述します。
  • 変数名・関数名: 分かりやすく、一貫性のある命名を心がけます。
  • インデント: 整ったインデント(字下げ)を使い、コードの階層構造を明確にします。
  • マジックナンバー・マジックストリングの回避: 直接的なIDやスラッグを埋め込むのではなく、定数や意味のある変数に置き換えることを検討します。ただし、single.php 内のIDやスラッグは比較的変更頻度が低いので、コメントを添えて直接記述することも許容される場合があります。
  • 関数化: 同じような処理が複数箇所で使われる場合、カスタム関数として functions.php (または専用のファイル) に切り出し、それを呼び出すようにします。

5.2. パフォーマンスへの配慮

  • データベースクエリの最小化: 条件分岐の中で、不必要なデータベースクエリを大量に実行しないように注意します。特にループ内でクエリを繰り返すのは避けるべきです。
  • PHPの処理負荷: 複雑な計算や処理を条件分岐内で大量に行うと、サーバーの負荷が高まります。可能な限り簡潔なコードを心がけ、重い処理はキャッシュで対応することを検討します。
  • 画像の最適化: 条件分岐によって表示される画像も、適切に圧縮・最適化されているか確認しましょう。

5.3. 子テーマの利用とテーマアップデート戦略

WordPressテーマのカスタマイズにおける最も重要なルールの一つは、「親テーマを直接編集しない」ことです。

  • 子テーマを作成する: 親テーマ(Twenty Twenty-Fourなどのデフォルトテーマや購入したテーマ)をカスタマイズする場合は、必ず子テーマを作成し、子テーマ内で single.php を編集・作成してください。
  • 親テーマの single.php を上書き: 子テーマのディレクトリに single.php を配置すると、親テーマの同名ファイルよりも優先して読み込まれます。既存の single.php をベースにカスタマイズする場合は、親テーマの single.php を子テーマにコピーし、それを編集します。
  • 親テーマのテンプレートパーツを上書き: get_template_part() で読み込んでいるテンプレートパーツ(例: template-parts/content-post.php)も、子テーマの同じパスに配置することで、親テーマのファイルを上書きしてカスタマイズできます。

この方法により、親テーマがアップデートされても、あなたのカスタマイズが失われることはありません。

5.4. セキュリティ意識を持った実装

  • エスケープ処理: ユーザー入力やデータベースから取得したデータを表示する際は、必ず適切なエスケープ処理(esc_html(), esc_attr(), esc_url() など)を施し、XSS(クロスサイトスクリプティング)などの脆弱性を防ぎます。
  • 権限チェック: current_user_can() などを利用して、表示・実行させる内容がユーザーの権限レベルに合致しているかを確認します。

これらのベストプラクティスを守ることで、一時的な解決策に終わらず、長期にわたって安定し、拡張可能なWordPressサイトを構築・運用することができます。

6. 実践!コピペで使えるコード例と詳細解説

ここからは、これまで学んだ知識を組み合わせた、より実践的なコード例を紹介します。コピペであなたの single.php に適用できるよう、丁寧な解説を添えています。

例1: カスタム投稿タイプ「イベント」と「ニュース」でレイアウトを切り替える

サイトに「イベント」と「ニュース」という2つのカスタム投稿タイプがあり、それぞれで表示する情報の優先順位やデザインが異なると仮定します。

実装方法: get_template_part()get_post_type() を組み合わせて、投稿タイプに応じたテンプレートファイルを読み込みます。

single.php の内容:

<?php get_header(); ?>

<main id="primary" class="site-main">

    <?php
    while ( have_posts() ) :
        the_post();

        // 現在の投稿タイプを取得
        $current_post_type = get_post_type();

        // 投稿タイプに基づいてテンプレートパーツを読み込む
        // 例: 'news' なら 'template-parts/content-single-news.php'
        // 'event' なら 'template-parts/content-single-event.php'
        // それ以外(デフォルトの投稿など)なら 'template-parts/content-single.php'
        get_template_part( 'template-parts/content-single', $current_post_type );

        // 前後の記事へのナビゲーションリンク
        the_post_navigation();

        // コメントセクション
        if ( comments_open() || get_comments_number() ) :
            comments_template();
        endif;

    endwhile; // End of the loop.
    ?>

</main><!-- #primary -->

<?php get_sidebar(); ?>
<?php get_footer(); ?>

template-parts/content-single-news.php の内容:

<article id="post-<?php the_ID(); ?>" <?php post_class( 'single-news-article' ); ?>>
    <header class="entry-header news-header">
        <p class="news-date"><?php echo get_the_date( 'Y年m月d日' ); ?></p>
        <?php the_title( '<h1 class="entry-title news-title">', '</h1>' ); ?>
    </header>

    <?php if ( has_post_thumbnail() ) : ?>
        <div class="post-thumbnail news-thumbnail">
            <?php the_post_thumbnail( 'large' ); // ニュース記事は大きめのアイキャッチ ?>
        </div>
    <?php endif; ?>

    <div class="entry-content news-content">
        <?php the_content(); ?>
    </div>

    <footer class="entry-footer news-footer">
        <p class="news-source">情報提供元: 〇〇広報部</p>
        <?php // ニュース記事に関連する追加情報やSNSシェアボタンなどを表示 ?>
    </footer>
</article>

template-parts/content-single-event.php の内容:

<article id="post-<?php the_ID(); ?>" <?php post_class( 'single-event-article' ); ?>>
    <header class="entry-header event-header">
        <?php the_title( '<h1 class="entry-title event-title">', '</h1>' ); ?>
        <p class="event-date">開催日: <?php echo esc_html( get_post_meta( get_the_ID(), 'event_date', true ) ); ?></p>
        <p class="event-location">場所: <?php echo esc_html( get_post_meta( get_the_ID(), 'event_location', true ) ); ?></p>
    </header>

    <div class="entry-content event-content">
        <?php the_content(); ?>
        <?php
        // ACFなどを使ってイベント詳細のカスタムフィールドを表示
        $event_details = get_field( 'event_details' ); // ACFのフィールド名が 'event_details' の場合
        if ( $event_details ) {
            echo '<div class="event-details">' . wp_kses_post( $event_details ) . '</div>';
        }
        ?>
    </div>

    <footer class="entry-footer event-footer">
        <?php
        $registration_link = get_post_meta( get_the_ID(), 'registration_link', true );
        if ( $registration_link ) : ?>
            <a href="<?php echo esc_url( $registration_link ); ?>" class="btn btn-primary event-registration-btn" target="_blank">
                イベントに申し込む
            </a>
        <?php endif; ?>
    </footer>
</article>

解説: single.php は、現在の投稿タイプを取得し、それに合わせたテンプレートパーツを読み込むだけになります。各投稿タイプに特有の表示ロジックやHTMLは、それぞれの content-single-{post_type}.php ファイルに分離されます。これにより、single.php は非常にスリムで管理しやすくなり、各カスタム投稿タイプ専用のファイルは独立して編集できるようになります。

例2: 特定のカテゴリー「キャンペーン」の記事に特別なバナーを表示する

サイトに「キャンペーン」というカテゴリーがあり、そのカテゴリーに属する記事には、読者の注意を引くための特別なバナーを記事本文の直前に表示したいとします。

実装方法: in_category() を使用してカテゴリーを判定し、バナーを挿入します。

single.php 内(the_post() の後):

<article id="post-<?php the_ID(); ?>" <?php post_class(); ?>>
    <header class="entry-header">
        <?php the_title( '<h1 class="entry-title">', '</h1>' ); ?>
        <div class="entry-meta">
            <span class="posted-on"><?php echo get_the_date(); ?></span>
            <span class="cat-links"><?php the_category(', '); ?></span>
        </div>
    </header>

    <div class="entry-content">
        <?php
        // 「キャンペーン」カテゴリーの場合に特別なバナーを表示
        if ( in_category( 'campaign' ) ) { // カテゴリーのスラッグを指定
            echo '<div class="campaign-banner">';
            echo '<img src="' . esc_url( get_template_directory_uri() . '/images/campaign-banner.jpg' ) . '" alt="特別キャンペーン実施中!">';
            echo '<p>このキャンペーンは期間限定です。お見逃しなく!</p>';
            echo '<a href="/campaign-page/" class="btn btn-campaign">詳細はこちら</a>';
            echo '</div>';
        }

        the_content(); // 通常の記事本文
        ?>
    </div>

    <footer class="entry-footer">
        <?php the_tags( '<span class="tag-links">タグ: ', ', ', '</span>' ); ?>
    </footer>
</article>

解説: the_content() の直前に in_category('campaign') で条件分岐を設けています。これにより、「キャンペーン」カテゴリーに属する記事の場合にのみ、特定の画像バナーとテキスト、ボタンが表示されます。他のカテゴリーの記事には何も影響しません。カテゴリーIDで指定する場合は in_category( 123 ) のように記述します。

例3: カスタムフィールドの値によって表示コンテンツを出し分ける

特定の記事で、ヘッダー直下に「特別な告知エリア」を表示するかどうかを、カスタムフィールドで制御したいとします。カスタムフィールドのキーは「show_announcement」で、値が true の場合に表示します。

実装方法: get_post_meta() を使ってカスタムフィールドの値を取得し、その値で分岐します。

single.php 内(the_post() の直後、または the_title() の前):

<?php
while ( have_posts() ) :
    the_post();

    // 'show_announcement' カスタムフィールドの値を取得
    // ACFを使っている場合は get_field('show_announcement') でもOK
    $show_announcement = get_post_meta( get_the_ID(), 'show_announcement', true );

    // カスタムフィールドの値が 'true' またはチェックボックスがオンの場合
    if ( '1' === $show_announcement || true === $show_announcement ) {
        echo '<div class="special-announcement">';
        echo '<h2>【重要なお知らせ】</h2>';
        echo '<p>この記事には、皆様にぜひ知っていただきたい重要な情報が含まれています。</p>';
        echo '<a href="/announcements/" class="btn btn-info">お知らせ一覧へ</a>';
        echo '</div>';
    }

    the_title( '<h1 class="entry-title">', '</h1>' );
    the_content();

    // ... その他の記事コンテンツ、コメントなど ...

endwhile;
?>

解説: get_post_meta() で現在の投稿の show_announcement フィールドの値を取得し、それが true に相当する場合(カスタムフィールドのタイプによって 1true になります)に告知エリアを表示します。これにより、記事ごとに管理画面から簡単に告知エリアの表示/非表示を切り替えられるようになります。

例4: 特定の投稿ID、またはスラッグの記事にのみ独自の要素を表示する

サイトオープン記念として公開した特定の記事(ID: 25、スラッグ: site-launch-campaign)に、特別な感謝メッセージとソーシャルシェアボタンを表示したいとします。

実装方法: is_single() を利用して、投稿IDまたはスラッグで分岐します。

single.php 内(the_content() の後):

<article id="post-<?php the_ID(); ?>" <?php post_class(); ?>>
    <header class="entry-header">
        <?php the_title( '<h1 class="entry-title">', '</h1>' ); ?>
    </header>

    <div class="entry-content">
        <?php the_content(); ?>
    </div>

    <footer class="entry-footer">
        <?php the_tags( '<span class="tag-links">タグ: ', ', ', '</span>' ); ?>

        <?php
        // IDが25の記事、またはスラッグが 'site-launch-campaign' の記事の場合に表示
        if ( is_single( 25 ) || is_single( 'site-launch-campaign' ) ) {
            echo '<div class="special-thanks-message">';
            echo '<h3>サイトオープン記念記事!</h3>';
            echo '<p>皆様のおかげで無事サイトをオープンすることができました。心より感謝申し上げます!</p>';
            echo '</div>';

            echo '<div class="social-share-buttons">';
            echo '<p>この記事をシェアして応援してください!</p>';
            // ここにFacebook, X(旧Twitter)などのシェアボタンのコードを記述
            echo '<a href="https://twitter.com/intent/tweet?url=' . urlencode( get_permalink() ) . '&text=' . urlencode( get_the_title() ) . '" target="_blank">Twitterでシェア</a>';
            echo '</div>';
        }
        ?>
    </footer>
</article>

解説: is_single( 25 ) || is_single( 'site-launch-campaign' ) という形で、OR条件 (||) を使って複数の条件(投稿IDまたはスラッグ)で分岐しています。これにより、いずれかの条件が満たされた場合にのみ、感謝メッセージとシェアボタンが表示されます。これは、非常に特定の記事にだけ特別な表示をさせたい場合に便利です。


これらのコード例はあくまで一例です。あなたのサイトの要件に合わせて、これらの条件分岐タグやテクニックを自由に組み合わせ、無限の可能性を探ってみてください。

7. まとめ:single.php 分岐をマスターして、あなたのサイトを次のレベルへ

この記事では、「WordPress single.php の条件分岐」について、5000字を超える大ボリュームで徹底的に解説してきました。

  • single.php の基本: テンプレート階層における役割と基本的な構造を理解しました。
  • 分岐の必要性: なぜ条件分岐が必要なのか、具体的なユースケースを通じてその重要性を認識しました。
  • 主要な条件分岐タグ: is_singular(), in_category(), has_tag(), is_single(), get_post_meta() など、多岐にわたるWordPressの強力な条件分岐タグの使い方を学びました。
  • 効率的な実装テクニック: get_template_part() によるモジュール化や、カスタムテンプレートファイルの活用など、プロが実践するスマートなコードの書き方を習得しました。
  • ベストプラクティス: 可読性、パフォーマンス、子テーマの利用、セキュリティといった、開発・運用における重要な注意点を押さえました。
  • 実践的なコード例: 学んだ知識を具体的なコードとして活用し、あなたのサイトに適用できるサンプルを確認しました。

single.php での条件分岐をマスターすることは、あなたのWordPressサイトの「個別記事ページ」を、単なるコンテンツ表示の枠を超え、それぞれの記事の特性や目的に合わせて最適化できることを意味します。これにより、読者にとってより魅力的で、使いやすく、そして目的を達成しやすいサイトを提供できるようになります。

最初は複雑に感じるかもしれませんが、一つ一つの条件分岐タグの役割を理解し、小さなカスタマイズから始めてみてください。そして、get_template_part() のようなテクニックを導入することで、コードは驚くほど整理され、あなたの開発効率も格段に向上するはずです。

さあ、今日からあなたは「WordPress single.php の達人」です!この知識を武器に、あなたのWordPressサイトを次のレベルへと進化させましょう。

もし途中でつまづいたり、さらに深掘りしたいテーマがあれば、ぜひコメントや他のリソースも参考にしてください。あなたのWordPressカスタマイズの旅が、素晴らしいものになることを願っています!

\ この記事をシェア/
この記事を書いた人
pekemalu
I love codes. I also love prompts (spells). But I get a lot of complaints (errors). I want to be loved by both of you as soon as possible.
Image