【WordPress】メインループで記事を表示する方法|have_posts・the_postの基本とpre_get_postsでのカスタマイズ

【WordPress】メインループを使って記事をループで処理して表示する方法 WordPress

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() でエスケープしましょう。

カスタムフィールド「color」を表示
<?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() は使わないでください
古い解説で見かける query_posts() は、メインクエリを丸ごと置き換えてページネーションを壊し、追加のDBクエリも発生します。WordPress公式も「使うべきでない」としています。メインループを変えるなら pre_get_posts、別のループが欲しいなら WP_Query を使いましょう。

メインループ自体を変える:pre_get_posts

「トップページに表示する記事をカテゴリー news に絞る」のようにメインループそのものを変えたい場合は、functions.phppre_get_posts を使います。これならページネーションも保たれます。

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() を必ず呼ぶのがポイントです。

WP_Query:news カテゴリーの別ループ
$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)

Qメインループとサブループの違いは何ですか?
AメインループはWordPressがURLに応じて自動的に用意するクエリhave_posts() / the_post() で処理するものです。サブループは WP_Query独自に作るクエリで、ループ後に wp_reset_postdata() のリセットが必要です。
Qthe_content() でショートコードも処理されますか?
Aはい。the_content() はデフォルトでショートコードやブロックを処理して出力します。生のコンテンツを変数で受け取って整形したい場合は apply_filters('the_content', get_the_content()) のように明示的にフィルターを適用してください。
Qループ後に wp_reset_postdata() を呼ばないとどうなりますか?
Aグローバルの $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_Querywp_reset_postdata()

基本構造を押さえ、カスタマイズは pre_get_postsWP_Query を使い分けるのが、ページネーションを壊さない正しいやり方です。