WP_Queryのサブループ後はwp_reset_postdata()でメインクエリの投稿へ戻す
公開日: 執筆:佐藤
WP_Queryでサブループを作り、the_post()を使った後は、ループの直後でwp_reset_postdata()を実行してください。the_post()が切り替えたグローバル変数$postを、メインクエリが示す投稿へ戻すためです。
リセットしないままthe_title()やthe_permalink()を呼ぶと、サブループの最後の投稿を参照することがあります。サブループの表示が正しくても、その後の見出しやリンクまで確認する必要があります。
the_post()は現在の投稿データを切り替える
WordPressのテンプレートタグは、明示した投稿IDだけでなく、グローバル変数$postを参照するものがあります。WP_Queryオブジェクトのthe_post()は、次の投稿を取り出し、その投稿を現在の投稿としてセットアップします。
たとえば、個別投稿の途中へ関連記事を表示するサブループを置くと、処理中の$postは関連記事へ切り替わります。ループを抜けただけでは、個別投稿へ自動で戻るとは限りません。
影響を受ける範囲を把握するには、サブループの後にあるテンプレートタグを調べます。投稿タイトル、URL、投稿IDを暗黙に参照する処理があれば、別の投稿データを使っていないか確認してください。
wp_reset_postdata()はサブループの直後に置く
次は説明用の仮例です。メインクエリの投稿を表示している途中で、別のWP_Queryを使って関連記事を三件取得します。
<?php
$related_query = new WP_Query(
array(
'post_type' => 'post',
'posts_per_page' => 3,
)
);
if ( $related_query->have_posts() ) :
while ( $related_query->have_posts() ) :
$related_query->the_post();
?>
<h3><a href="<?php the_permalink(); ?>"><?php the_title(); ?></a></h3>
<?php
endwhile;
endif;
wp_reset_postdata();
?>
wp_reset_postdata()は、サブループのif文の外、サブループが終わった直後へ置いています。取得結果がある場合だけ後片付けする、という条件を増やさず、別のクエリを扱う処理とリセットを一組にするためです。
WordPress 4.1.1のquery.phpでは、wp_reset_postdata()がメインクエリの現在の投稿へグローバル変数$postを戻します。サブループの表示内容を消す関数でも、取得した投稿をデータベースから削除する関数でもありません。
wp_reset_query()とは戻す対象が違う
wp_reset_postdata()とwp_reset_query()は名前が似ていますが、戻す対象が違います。
| 関数 | 主な用途 | 戻す対象 |
|---|---|---|
wp_reset_postdata() |
別のWP_Queryでサブループを実行した後 |
グローバル変数$post |
wp_reset_query() |
query_posts()などでグローバルなクエリ自体を置き換えた後 |
グローバルな$wp_queryと投稿データ |
サブループのためにnew WP_Query()を使っただけなら、メインクエリそのものを置き換えていません。必要なのはwp_reset_postdata()です。名前が強そうだからという理由でwp_reset_query()へ替えないでください。
そもそも投稿一覧の条件を変えたい場合と、ページ内に別の一覧を追加したい場合を分けます。前者はメインクエリの条件を扱い、後者は別のWP_Queryと投稿データの復元を扱います。
入れ子にする前に一つのサブループで確認する
複数のサブループを入れ子にすると、どのクエリの投稿へ戻したいのかが分かりにくくなります。まず一つのサブループだけを置き、次の順で確認してください。
- サブループ内のタイトルとURLが取得対象に合うか確認する
- ループ直後に
wp_reset_postdata()を置く - リセット後にメイン投稿のタイトル、URL、投稿IDが保たれているか確認する
- 問題がなければ、必要な絞り込み条件や表示項目を追加する
確認用にget_the_ID()を一時表示すると、サブループの前後でどの投稿が現在値になっているかを比べられます。公開画面へ確認用のIDを残さないようにしてください。
テーマ制作を委託する場合は、サブループを置いたテンプレート名、使ったWP_Query、リセット位置、直後にあるテンプレートタグを引き継ぎます。関連記事が表示できたことだけを完了条件にせず、メイン投稿のパンくず、見出し、前後リンクなどが別の投稿へ変わっていないことまで確認します。
最初の一手は、テーマ内のnew WP_Queryを一か所選び、対応するwp_reset_postdata()がループ直後にあるかを調べることです。なければ追加し、その後にあるテンプレートタグがメイン投稿を参照することを確認してください。
関連記事

