WordPressのループとは|have_posts と the_post の基本と注意点

結論

ループ(The Loop)は、WordPress が表示する投稿を1件ずつ取り出して、タイトルや本文を出力するための決まった書き方です。テーマのテンプレートでは、次の形をそのまま使います。

<?php if ( have_posts() ) : ?>
    <?php while ( have_posts() ) : the_post(); ?>
        <h2><?php the_title(); ?></h2>
        <?php the_content(); ?>
    <?php endwhile; ?>
<?php else : ?>
    <p>記事がありません。</p>
<?php endif; ?>

have_posts() は「まだ表示する投稿があるか」を調べ、the_post() は「次の投稿を、今の投稿としてセットする」関数です。ただし、別の条件で投稿を取り出す2つ目のループを書いたときは、終わったあとに wp_reset_postdata() の使い方|説明・引数・注意点 で元に戻します。

原因・仕組み

WordPress は、URL(どのページを開いたか)から「表示すべき投稿の一覧」をあらかじめ取得しています。これをメインクエリと呼びます。ループは、その一覧を上から順に読む仕組みです。

部品 やさしい言い換え 役割
have_posts() 「次はある?」 残りの投稿があれば true
the_post() 「次の1件を手に取る」 次の投稿を「今の投稿」にする
テンプレートタグ 「手に取った1件の情報を出す」 the_title() の使い方|説明・引数・注意点、the_content() の使い方|説明・引数・注意点、the_permalink() の使い方|説明・引数・注意点 など

Theme Handbook は、ループの中で使う代表的なテンプレートタグとして、the_title()、the_content()、the_excerpt()、the_category()、the_author()、the_tags()、the_post_thumbnail() などを挙げています。これらは「今の投稿」の情報を出すので、the_post() の後で使います。

2つ目のループには、WP_Query を使います(WP_Query クラスの使い方|説明・引数・注意点)。Theme Handbook は、2つ目のループの後に wp_reset_postdata() で、グローバルな $post(今の投稿)を戻すよう説明しています。同じ一覧をもう一度回したいときは rewind_posts() を使います。

手順(サンプルコード:2つ目のループ)

<?php
$recent = new WP_Query( array( 'posts_per_page' => 3 ) );
if ( $recent->have_posts() ) :
    echo '<ul>';
    while ( $recent->have_posts() ) : $recent->the_post();
        echo '<li><a href="' . esc_url( get_permalink() ) . '">' . esc_html( get_the_title() ) . '</a></li>';
    endwhile;
    echo '</ul>';
    wp_reset_postdata();
endif;

$recent->have_posts() のように、2つ目のループでは作ったクエリの変数から呼びます。出力は esc_html() の使い方|説明・引数・注意点 などでエスケープします。

動作確認(検証環境と結果)

WordPress 7.1.3(ja)、PHP 8.2.12 の CLI 検証環境で、投稿を3件(Loop A・B・C)作って確かめました。

確認したこと 結果
ループで3件を順に出力 Loop A / Loop B / Loop C の順に出た
ループを最後まで回した直後に have_posts() を呼ぶ true が返った(最後まで進むと内部で先頭に巻き戻るため)
rewind_posts() の後に the_post() 今の投稿は Loop A に戻った
2つ目のループ(Loop C だけ)の直後に get_the_title() Loop C(元の投稿から変わったまま)
その後 wp_reset_postdata() を呼んで get_the_title() Loop A(元の投稿に戻った)

2行目の結果から、ループの後に同じ while ( have_posts() ) をもう一度書くと、もう一度最初から回ってしまうことが分かります。4〜5行目は、wp_reset_postdata() を忘れると、その後のタイトル表示などが2つ目のループの投稿のままになることを示しています。確認後、テスト用の投稿は削除しました。

WordPressのループの注意点

  • the_post() を書き忘れない: while ( have_posts() ) の中で the_post() を呼ばないと、次の投稿に進まず、同じ処理が止まらなくなります。
  • query_posts() は使わない: メインクエリを書き換えたいときは pre_get_posts を使います(posts_per_page が効かない原因と pre_get_posts の正しい書き方)。Theme Handbook も、wp_reset_query() が必要なのは非推奨の query_posts() を使った場合だけとしています。
  • ループの外のテンプレートタグ: 今の投稿が無い場所では、タイトルなどは空になります(検証では空文字が返りました)。

WordPressのループでよくあるミス

  • 2つ目のループで have_posts() と書き、作ったクエリではなくメインクエリを見てしまう。
  • wp_reset_postdata() を忘れて、サイドバーやフッターの表示がずれる。
  • endwhile と endif の対応を崩して、構文エラーになる。
  • 一覧ページで the_content() を使い、本文が全部出て長くなる。一覧では the_excerpt() を使う。

WordPressのループのチェックリスト

  • [ ] if ( have_posts() ) と while ( have_posts() ) : the_post(); の形になっている
  • [ ] 投稿が無いとき(else)の表示を用意した
  • [ ] 2つ目のループは WP_Query の変数から呼んでいる
  • [ ] 2つ目のループの後に wp_reset_postdata() がある
  • [ ] 出力をエスケープしている

WordPressのループのFAQ(よくある質問)

Q. ループは1ページに何回書いてもよいですか?
A. 書けます。メインのループは1つで、追加の一覧は WP_Query で作り、それぞれの後に wp_reset_postdata() を呼びます。

Q. 表示件数はどこで決まりますか?
A. メインクエリの件数は、設定 → 表示設定 の「1ページに表示する最大投稿数」が基本です。テーマ側で変えるなら pre_get_posts を使います。

Q. get_posts() とループの関係は?
A. get_posts() は投稿の配列を返す関数で、the_post() を使う通常のループとは書き方が違います。違いは get_posts と WP_Query の違い|使い分けと実測結果 を参照してください。

筆者の見解(WordPressのループ)

ループは、WordPress のテーマを読むときに必ず出てくる「型」なので、意味を理解する前に形ごと覚えてしまうのがよいと考えます。そのうえで、つまずきやすいのは2つ目のループの後始末で、表示が少しずれるだけなので原因に気づきにくいのが厄介です。「new WP_Query を書いたら、必ず wp_reset_postdata をセットで書く」と決めておくのが、最も効く予防策だと私は思います。

WordPressのループの関連項目

出典(一次情報)

タイトルとURLをコピーしました