2026年5月20日

2026年5月20日

WordPressのループをカスタマイズする方法

はじめに

WordPressの「ループ(The Loop)」は投稿を繰り返し表示する仕組みです。メインループは have_posts()the_post() で動作しますが、WP_Query を使えば任意の条件で独自のサブループを作れます。

症状・原因

  • 特定カテゴリの投稿だけ一覧表示したい
  • 同ページに複数の投稿リストを表示したい
  • ループ内のレイアウトをカード型にしたい
  • サブループでページネーションが効かない

解決手順

ステップ1:メインループの基本

// index.php・archive.php
<?php if (have_posts()) : ?>
    <div class="post-grid">
        <?php while (have_posts()) : the_post(); ?>
            <article id="post-<?php the_ID(); ?>" <?php post_class('card'); ?>>
                <?php if (has_post_thumbnail()) : ?>
                    <a href="<?php the_permalink(); ?>">
                        <?php the_post_thumbnail('medium'); ?>
                    </a>
                <?php endif; ?>
                <div class="card-body">
                    <h2 class="card-title">
                        <a href="<?php the_permalink(); ?>"><?php the_title(); ?></a>
                    </h2>
                    <p class="card-excerpt"><?php the_excerpt(); ?></p>
                    <time datetime="<?php echo get_the_date('c'); ?>">
                        <?php echo get_the_date(); ?>
                    </time>
                </div>
            </article>
        <?php endwhile; ?>
    </div>
    <?php the_posts_pagination(); ?>
<?php else : ?>
    <p>投稿が見つかりません。</p>
<?php endif; ?>

ステップ2:WP_Queryでカスタムループを作る

// サイドバーや任意の場所に新着投稿を表示
$recent_query = new WP_Query([
    'post_type'      => 'post',
    'posts_per_page' => 5,
    'orderby'        => 'date',
    'order'          => 'DESC',
    'no_found_rows'  => true, // ページネーション不要なら高速化
]);

if ($recent_query->have_posts()) :
    echo '<ul class="recent-posts">';
    while ($recent_query->have_posts()) : $recent_query->the_post(); ?>
        <li>
            <a href="<?php the_permalink(); ?>"><?php the_title(); ?></a>
            <time><?php echo get_the_date(); ?></time>
        </li>
    <?php endwhile;
    echo '</ul>';
endif;

// 必須: サブループ後はメインクエリをリセット
wp_reset_postdata();

ステップ3:カテゴリ・タグ・カスタムフィールドで絞り込む

// カテゴリスラッグで絞り込み
$news_query = new WP_Query([
    'post_type'      => 'post',
    'posts_per_page' => 6,
    'category_name'  => 'news', // カテゴリスラッグ
]);

// タグで絞り込み
$tag_query = new WP_Query([
    'tag_slug__in'   => ['wordpress', 'php'],
    'posts_per_page' => 4,
]);

// カスタムフィールドで絞り込み(今日以降のイベント)
$event_query = new WP_Query([
    'post_type'      => 'event',
    'posts_per_page' => 10,
    'meta_key'       => '_event_date',
    'orderby'        => 'meta_value',
    'order'          => 'ASC',
    'meta_query'     => [[
        'key'     => '_event_date',
        'value'   => date('Y-m-d'),
        'compare' => '>=',
        'type'    => 'DATE',
    ]],
]);

ステップ4:ループのカードレイアウト(CSS)

.post-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
    gap: 1.5rem;
}

.card {
    background: #fff;
    border: 1px solid #e2e4e7;
    border-radius: 8px;
    overflow: hidden;
    transition: box-shadow 0.2s;
}

.card:hover {
    box-shadow: 0 4px 16px rgba(0,0,0,0.12);
}

.card img {
    width: 100%;
    aspect-ratio: 16/9;
    object-fit: cover;
}

.card-body {
    padding: 1.25rem;
}

注意事項

  • サブループ(WP_Query)を使った後は必ず wp_reset_postdata() を呼んでください。メインループのグローバル $post が上書きされたままになります
  • no_found_rows: true はページネーション不要のサブループで使うとSQLのCOUNTクエリを省略して高速化できます
  • メインループのページネーションには the_posts_pagination()paginate_links() を使います。サブループにはページネーションは通常設けません

まとめ

メインループは have_posts() + the_post() で動作します。独自のサブループは WP_Query で作成し、終了後に wp_reset_postdata() を呼ぶのが必須です。no_found_rows: true でページネーション不要な場合のパフォーマンスを改善できます。

お気軽にご相談ください

お見積りへ お問い合わせへ