WordPressがページに記事を一覧表示する仕組みがメインループ(the Loop)です。have_posts() と the_post() を使って、現在のページに該当する記事を1件ずつ取り出して表示します。この記事では、基本構造から、各情報の表示、そして正しいカスタマイズ方法までを解説します。
- メインループの基本構造(
have_posts()/the_post()) - タイトル・本文・抜粋・カスタムフィールドの表示
- メインループを変更する正しい方法(
pre_get_posts) - 別のループを作る方法(
WP_Query)と query_posts() を使わない理由
メインループとは
メインループは、現在のURLに応じてWordPressが自動的に用意するクエリの結果を1件ずつ処理する仕組みです。トップページなら最新記事一覧、カテゴリーページならそのカテゴリーの記事、個別記事ページならその記事、というように、ページの種類に合った記事が入っています。
メインループの基本構造
メインループの基本形は次のとおりです。have_posts() で「まだ処理していない記事があるか」を判定し、the_post() で次の記事をセットします。
<?php if (have_posts()) : while (have_posts()) : the_post(); ?> <?php // ここに各記事の表示コードを書く ?> <?php endwhile; else : ?> <p>記事が見つかりませんでした。</p> <?php endif; ?>
タイトルと本文を表示する
ループ内で the_title()・the_content() などのテンプレートタグを使うと、現在の記事の情報を出力できます。
<?php if (have_posts()) : while (have_posts()) : the_post(); ?> <h2><?php the_title(); ?></h2> <div><?php the_content(); ?></div> <?php endwhile; else : ?> <p>記事が見つかりませんでした。</p> <?php endif; ?>
取得できる情報(ID・抜粋・パーマリンク・著者など)と関数の一覧は記事の情報を取得する方法、投稿IDの取得は投稿IDを取得するさまざまな方法にまとめています。
本文ではなく抜粋だけ表示する
一覧ページで本文全体ではなく冒頭の要約だけ見せたい場合は、the_content() の代わりに the_excerpt() を使います。
<?php if (have_posts()) : while (have_posts()) : the_post(); ?> <h2><?php the_title(); ?></h2> <div><?php the_excerpt(); ?></div> <?php endwhile; endif; ?>
カスタムフィールドの値を表示する
ループ内では get_post_meta() で現在の記事のカスタムフィールドを取得できます。出力時は esc_html() でエスケープしましょう。
<?php if (have_posts()) : while (have_posts()) : the_post(); ?> <h2><?php the_title(); ?></h2> <p>色: <?php echo esc_html(get_post_meta(get_the_ID(), 'color', true)); ?></p> <?php endwhile; endif; ?>
メインループの中身を変える(query_posts は使わない)
古い解説で見かける
query_posts() は、メインクエリを丸ごと置き換えてページネーションを壊し、追加のDBクエリも発生します。WordPress公式も「使うべきでない」としています。メインループを変えるなら pre_get_posts、別のループが欲しいなら WP_Query を使いましょう。メインループ自体を変える:pre_get_posts
「トップページに表示する記事をカテゴリー news に絞る」のようにメインループそのものを変えたい場合は、functions.php で pre_get_posts を使います。これならページネーションも保たれます。
add_action('pre_get_posts', function ($query) {
// 管理画面とサブクエリは対象外
if (is_admin() || !$query->is_main_query()) {
return;
}
// トップページのメインループだけ news カテゴリーに絞る
if ($query->is_home()) {
$query->set('category_name', 'news');
}
});
pre_get_posts を使った絞り込み・除外の実例は絞り込み検索機能を実装する方法、一覧ページに特定の投稿を表示しない方法も参考になります。
別のループを作る:WP_Query
メインループとは別に、サイドバーやページの一部に独自の一覧を出したい場合はWP_Query で新しいクエリを作ります。ループの最後に wp_reset_postdata() を必ず呼ぶのがポイントです。
$news = new WP_Query(array('category_name' => 'news'));
if ($news->have_posts()) :
while ($news->have_posts()) : $news->the_post();
the_title('<h2>', '</h2>');
endwhile;
wp_reset_postdata(); // メインループに状態を戻す(必須)
endif;
AND/OR/NOTを組み合わせた複雑な条件はWP_Queryで複雑な条件検索を実装する方法で詳しく解説しています。
よくある質問(FAQ)
have_posts() / the_post() で処理するものです。サブループは WP_Query で独自に作るクエリで、ループ後に wp_reset_postdata() のリセットが必要です。the_content() はデフォルトでショートコードやブロックを処理して出力します。生のコンテンツを変数で受け取って整形したい場合は apply_filters('the_content', get_the_content()) のように明示的にフィルターを適用してください。$post が変更されたままになり、ループ後の the_title() や the_permalink() が最後に処理した記事の情報を返してしまいます。サブループ(WP_Query)の直後には必ず wp_reset_postdata(); を呼びましょう。まとめ
- 基本:
if (have_posts()) : while (have_posts()) : the_post(); - 表示:
the_title()/the_content()/the_excerpt()/get_post_meta() - メインループを変える:
pre_get_posts(query_posts は使わない) - 別ループ:
WP_Query+wp_reset_postdata()
基本構造を押さえ、カスタマイズは pre_get_posts と WP_Query を使い分けるのが、ページネーションを壊さない正しいやり方です。

