• WP_Queryのサブループ後はwp_reset_postdata()でメインクエリの投稿へ戻す

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と投稿データの復元を扱います。

入れ子にする前に一つのサブループで確認する

複数のサブループを入れ子にすると、どのクエリの投稿へ戻したいのかが分かりにくくなります。まず一つのサブループだけを置き、次の順で確認してください。

  1. サブループ内のタイトルとURLが取得対象に合うか確認する
  2. ループ直後にwp_reset_postdata()を置く
  3. リセット後にメイン投稿のタイトル、URL、投稿IDが保たれているか確認する
  4. 問題がなければ、必要な絞り込み条件や表示項目を追加する

確認用にget_the_ID()を一時表示すると、サブループの前後でどの投稿が現在値になっているかを比べられます。公開画面へ確認用のIDを残さないようにしてください。

テーマ制作を委託する場合は、サブループを置いたテンプレート名、使ったWP_Query、リセット位置、直後にあるテンプレートタグを引き継ぎます。関連記事が表示できたことだけを完了条件にせず、メイン投稿のパンくず、見出し、前後リンクなどが別の投稿へ変わっていないことまで確認します。

最初の一手は、テーマ内のnew WP_Queryを一か所選び、対応するwp_reset_postdata()がループ直後にあるかを調べることです。なければ追加し、その後にあるテンプレートタグがメイン投稿を参照することを確認してください。

戻る