閉じる

WordPress投稿ページ(single.php)の作り方とカスタマイズ:最新の記述ルールとテンプレート階層

WordPressでブログやニュースサイトを構築する際、サイトの核となるのが各記事を表示するための「投稿ページ」です。

この投稿ページの表示を制御するテンプレートファイルがsingle.phpです。

WordPressには数多くのテンプレートファイルが存在しますが、single.phpの仕組みを正しく理解し、最新の記述ルールに基づいたカスタマイズを行うことは、サイトの運用性やSEO、さらにはユーザー体験の向上に直結します。

2026年現在、WordPressはブロックエディタをベースとしたフルサイト編集(FSE)が主流となっていますが、自由度の高いデザインや複雑なロジックを必要とするプロジェクトでは、依然としてPHPベースのテーマ開発が重要な役割を担っています。

本記事では、single.phpの作り方の基礎から、テンプレート階層の優先順位、そして現代的なコーディングベストプラクティスまでを詳しく解説します。

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

WordPressには、表示されるページの種類に応じてどのテンプレートファイルを使用するかを決定する「テンプレート階層」という仕組みがあります。

single.phpはこの階層の中で、個別投稿ページを表示するための標準的なテンプレートとして定義されています。

テンプレートの優先順位

ユーザーが特定の投稿(post)にアクセスした際、WordPressは以下の順序でテンプレートファイルを探します。

  1. single-{post_type}-{slug}.php:特定の投稿タイプかつ特定のスラッグを持つ投稿
  2. single-{post_type}.php:特定の投稿タイプ(例:single-news.phpなど)
  3. single.php:すべての個別投稿のデフォルト
  4. singular.php:投稿および固定ページ(page)の共通テンプレート
  5. index.php:最終的なフォールバック(代替)ファイル

このように、single.phpは個別投稿を表示するための中心的な役割を果たしますが、特定のカテゴリーやカスタム投稿タイプごとにデザインを分けたい場合は、より優先度の高いファイル名を作成することで、柔軟に表示を切り替えることが可能です。

singular.phpとの使い分け

近年では、投稿ページと固定ページで共通のデザインを採用する場合にsingular.phpを用いるケースも増えています。

しかし、投稿ページには「公開日」「カテゴリー」「タグ」「前後記事へのナビゲーション」など、固定ページにはない要素が多く含まれるため、保守性と可読性を考慮するとsingle.phpを独立させて作成するのが一般的です。

single.phpの基本構造と必須の記述

single.phpを作成するにあたって、最低限含めるべきコードの構成を確認しましょう。

WordPressの標準的なループ処理(The Loop)を用いることで、データベースから取得した記事情報を正しく表示できます。

基本的なコードスケルトン

以下は、single.phpの最も標準的な構成例です。

PHP
<?php
/**
 * The template for displaying all single posts
 *
 * @package WordPress
 * @subpackage Your_Theme_Name
 * @since 1.0.0
 */

// ヘッダーの読み込み
get_header(); ?>

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

    <?php
    /* 
     * WordPressループの開始
     * 投稿データが存在するかを確認し、存在する間は繰り返し処理を行う
     */
    if ( have_posts() ) :
        while ( have_posts() ) :
            the_post();

            // テンプレートパーツの読み込み(content-single.phpなど)
            get_template_part( 'template-parts/content', get_post_type() );

            // 投稿ナビゲーション(前後の記事へのリンク)
            the_post_navigation(
                array(
                    'prev_text' => '<span class="nav-subtitle">' . esc_html__( 'Previous:', 'textdomain' ) . '</span> <span class="nav-title">%title</span>',
                    'next_text' => '<span class="nav-subtitle">' . esc_html__( 'Next:', 'textdomain' ) . '</span> <span class="nav-title">%title</span>',
                )
            );

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

        endwhile;
    endif;
    ?>

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

<?php
// サイドバーとフッターの読み込み
get_sidebar();
get_footer();

各関数の役割

上記のコードで使用されている主要な関数の役割を整理します。

関数名役割
get_header()header.phpファイルを読み込みます。
have_posts()表示すべき投稿があるかどうかを判定します。
the_post()現在の投稿データをセットし、テンプレートタグを使用可能にします。
get_template_part()別のPHPファイルをパーツとして読み込み、コードの再利用性を高めます。
the_post_navigation()前後の記事へのリンクを自動生成します。
get_footer()footer.phpファイルを読み込みます。

2026年基準のセキュアなコーディングとエスケープ処理

2026年のWeb開発において、セキュリティ対策は欠かせない要素です。

WordPress開発でも、「すべての出力をエスケープする」という原則を徹底する必要があります。

出力時のエスケープ処理

データベースから取得した値を表示する際は、必ず適切なエスケープ関数を通します。

これにより、クロスサイトスクリプティング(XSS)などの脆弱性を防ぐことができます。

PHP
<article id="post-<?php the_ID(); ?>" <?php post_class(); ?>>
    <header class="entry-header">
        <?php
        // タイトルの表示。エスケープ処理を含んだ関数を使用
        if ( is_singular() ) :
            the_title( '<h1 class="entry-title">', '</h1>' );
        else :
            the_title( '<h2 class="entry-title"><a href="' . esc_url( get_permalink() ) . '">', '</a></h2>' );
        endif;
        ?>

        <div class="entry-meta">
            <span class="posted-on">
                <time datetime="<?php echo esc_attr( get_the_date( 'c' ) ); ?>">
                    <?php echo esc_html( get_the_date() ); ?>
                </time>
            </span>
            <span class="byline">
                <?php echo esc_html( get_the_author() ); ?>
            </span>
        </div>
    </header>

    <div class="entry-content">
        <?php
        // コンテンツの表示。the_contentは内部で安全に処理されるため直接呼び出し可能
        the_content();
        ?>
    </div>
</article>

インライン要素の扱い

属性値(hrefやsrcなど)に動的な値を入れる場合は、必ずesc_url()esc_attr()を使用してください。

これにより、不正なスクリプトの混入を未然に防ぐことが可能です。

テンプレートパーツによるコードの共通化

single.phpにすべてのHTML構造を記述すると、コードが肥大化しメンテナンスが困難になります。

そこで活用すべきなのがテンプレートパーツ化です。

template-partsディレクトリの活用

一般的に、投稿のメインコンテンツ部分はtemplate-parts/content-single.phpといった別ファイルに切り出します。

PHP
// single.php内での呼び出し例
get_template_part( 'template-parts/content', 'single' );

このように記述することで、もし将来的に「特定の投稿タイプだけレイアウトを変えたい」といった要望が出た際も、content-news.phpのような新しいパーツを作成するだけで済み、single.php本体のロジックを汚さずに済みます。

高度なカスタマイズ:メタ情報とタクソノミーの表示

投稿ページにおいて、記事の内容と同じくらい重要なのが、その記事に紐付くメタ情報(カテゴリー、タグ、カスタムフィールド)の表示です。

カテゴリーとタグのリスト表示

カテゴリー情報を取得し、デザインに合わせて出力するコード例です。

PHP
<div class="post-categories">
    <?php
    $categories = get_the_category();
    if ( ! empty( $categories ) ) {
        echo '<ul class="cat-list">';
        foreach ( $categories as $category ) {
            echo '<li><a href="' . esc_url( get_category_link( $category->term_id ) ) . '" class="cat-link">' . esc_html( $category->name ) . '</a></li>';
        }
        echo '</ul>';
    }
    ?>
</div>
HTML
<div class="post-categories">
    <ul class="cat-list">
        <li><a href="https://example.com/category/news/" class="cat-link">ニュース</a></li>
        <li><a href="https://example.com/category/tech/" class="cat-link">テクノロジー</a></li>
    </ul>
</div>

カスタムフィールドの活用

特定の投稿にだけ追加情報を表示したい場合、カスタムフィールド(Advanced Custom Fieldsなど)を使用することが多いでしょう。

PHP 8.x以降の厳格な型判定を意識し、値が存在するかどうかをチェックしてから出力します。

PHP
<?php
// カスタムフィールド 'sub_title' を取得
$sub_title = get_post_meta( get_the_ID(), 'sub_title', true );

if ( ! empty( $sub_title ) ) : ?>
    <p class="sub-title"><?php echo esc_html( $sub_title ); ?></p>
<?php endif; ?>

ユーザー回遊率を高める関連記事の表示

single.phpにおいて、読者が記事を読み終えた後に関連する他の記事を提案することは、サイトの離脱率を下げ、滞在時間を延ばすために極めて重要です。

同一カテゴリーの最新記事を取得する

WP\_Queryを使用して、現在表示している記事と同じカテゴリーに属する他の記事を動的に取得します。

PHP
<?php
$current_post_id = get_the_ID();
$categories = get_the_category();

if ( $categories ) {
    $cat_ids = array();
    foreach ( $categories as $category ) {
        $cat_ids[] = $category->term_id;
    }

    $args = array(
        'category__in'   => $cat_ids,
        'post__not_in'   => array( $current_post_id ),
        'posts_per_page' => 3,
        'orderby'        => 'rand', // ランダムに取得
    );

    $related_query = new WP_Query( $args );

    if ( $related_query->have_posts() ) : ?>
        <section class="related-posts">
            <h2>関連記事</h2>
            <div class="related-grid">
                <?php while ( $related_query->have_posts() ) : $related_query->the_post(); ?>
                    <div class="related-item">
                        <a href="<?php the_permalink(); ?>">
                            <?php if ( has_post_thumbnail() ) : ?>
                                <?php the_post_thumbnail( 'medium' ); ?>
                            <?php endif; ?>
                            <h3><?php the_title(); ?></h3>
                        </a>
                    </div>
                <?php endwhile; ?>
            </div>
        </section>
    <?php
    endif;
    wp_reset_postdata(); // 投稿データをリセット
}

このコードのポイントは、wp_reset_postdata()を必ず呼び出す点にあります。

これを行わないと、メインループ(single.php本来の投稿データ)に影響を与えてしまい、フッターなどの表示が崩れる原因となります。

ブロックテーマ時代におけるsingle.phpの運用

2026年現在、WordPress開発の主流は「ブロックテーマ」へとシフトしています。

しかし、従来の「クラシックテーマ」の手法でsingle.phpをカスタマイズする必要がある場面も依然として存在します。

ブロックパターンとの連携

single.phpの中で、特定のデザイン済みブロックグループ(ブロックパターン)を呼び出すことができます。

これにより、PHPコードの堅牢性とブロックエディタの柔軟性を両立させることが可能です。

PHP
<?php
// PHPテンプレート内で特定のブロックパターンを呼び出す例
if ( function_exists( 'register_block_pattern' ) ) {
    echo do_blocks( '<!-- wp:pattern {"slug":"my-theme/post-footer-cta"} /-->' );
}
?>

FSE(フルサイト編集)との比較

フルサイト編集対応テーマでは、single.phpの代わりにtemplates/single.htmlが使用されます。

しかし、複雑な条件分岐(特定のユーザー権限のみ表示、外部APIとの連携など)を行う場合は、PHPテンプレートであるsingle.phpの方が圧倒的に制御しやすいというメリットがあります。

用途に応じて、どちらの手法が最適かを判断することがプロのエンジニアには求められます。

パフォーマンス最適化とCore Web Vitalsへの配慮

投稿ページは画像や埋め込みコンテンツが多くなりがちです。

single.phpを設計する段階で、パフォーマンス面での最適化を考慮しておく必要があります。

画像の遅延読み込みとサイズ指定

WordPress 5.5以降、画像にはデフォルトでloading="lazy"が付与されますが、single.php内でアイキャッチ画像を表示する際は、LCP(Largest Contentful Paint)への影響を最小限にするため、最初の1枚については遅延読み込みを無効化する検討も必要です。

PHP
<?php
// アイキャッチ画像の表示(LCP対策としてfetchpriority属性を検討)
if ( has_post_thumbnail() ) {
    the_post_thumbnail( 'full', array(
        'fetchpriority' => 'high',
        'loading'       => 'eager',
        'alt'           => the_title_attribute( array( 'echo' => false ) ),
    ) );
}
?>

スクリプトの最適化

特定の投稿ページでのみ必要なJavaScriptやCSSがある場合は、wp_enqueue_scriptsアクションフックを使い、条件分岐を用いて読み込みを制限します。

これにより、サイト全体の読み込み速度を向上させることができます。

PHP
// functions.phpなどでの記述例
function my_theme_enqueue_post_scripts() {
    if ( is_single() ) {
        wp_enqueue_script( 'post-specific-script', get_template_directory_uri() . '/js/post.js', array(), '1.0', true );
    }
}
add_action( 'wp_enqueue_scripts', 'my_theme_enqueue_post_scripts' );

まとめ

WordPressの投稿ページを司るsingle.phpは、サイトの情報を伝える上で最も重要なテンプレートの一つです。

2026年の開発基準においては、単に記事を表示するだけでなく、以下の点に留意することが求められます。

  • テンプレート階層を理解し、適切なファイル分割を行うこと。
  • エスケープ処理を徹底し、セキュアなコードを記述すること。
  • WP_Queryを活用し、関連性の高い情報をユーザーに提供すること。
  • パフォーマンスを意識し、画像やスクリプトの読み込みを最適化すること。

クラシックなPHPベースのカスタマイズ技術と、最新のブロックエディタの機能を組み合わせることで、運用のしやすさと高いユーザー体験を兼ね備えた投稿ページを実現できます。

本記事で紹介した基本構造や最新の記述ルールを参考に、ぜひ自身のプロジェクトに最適なsingle.phpを構築してください。

クラウドSSLサイトシールは安心の証です。

URLをコピーしました!