結論
ループ(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のループの関連項目
- have_posts() の使い方|説明・引数・注意点
- the_post() の使い方|説明・引数・注意点
- wp_reset_postdata() の使い方|説明・引数・注意点
- WP_Query クラスの使い方|説明・引数・注意点
- テンプレート階層とは|WordPressが表示ファイルを選ぶ順番
