取得した記事をリセットする wp_reset_query と wp_reset_postdata

更新2022/01/03

WordPressの投稿一覧を表示させるときにループを使いますが、そのループをリセットしたい時に使えるのが wp_reset_query() と wp_reset_postdata()。

この2つの使い方と違いをメモしていきます。

wquery_postを使ったら wp_reset_query

wp_reset_query() は以下のように定義されています。

function wp_reset_query() {
  $GLOBALS['wp_query'] = $GLOBALS['wp_the_query'];
  wp_reset_postdata();
}

【コードリファレンス】 wp_reset_query() – GUAVAmemo

どういうことをしているかというと、グローバル変数$wp_query の内容を元に戻して、取得した投稿データをリセットします。

wp_reset_query() はその名の通りWPクエリをリセットするものです。$wp_query を変更した時、その中のデータを変更した場合などは、変更後にリセットする必要があります。

query_posts() でループを回したらリセットする

query_posts() を使って投稿表示をした場合、このwp_reset_query() を使います。

<?php
  $args = [
    'post_type' => 'post',
    'posts_per_page' => 5,
  ];
  // 投稿の呼び出しに query_posts
  query_posts($args);
  if (have_posts()): while (have_posts()): the_post();
?>
<?php endwhile ?>
<?php endif ?>
<!-- 最後にリセットする -->
<?php wp_reset_query(); ?>

query_posts() は $wp_query を書き換えるコードです。
$wp_query を元に動作しているものは多いので、書き換えた後リセットしないと、そのほかのところで正常に動作しなくなることがあります。

query_posts() を使っていないなら、wp_reset_query() は必要ありません。

新規でコードを書くなら query_posts は使わないようにする

wp_reset_query() はquery_posts() を使用した場合に使うものですが、そもそも query_posts() を使うのは非推奨とされています。
query_posts() はWordPressを動かしている大元のコードを変更するからです。

【関連記事】query_posts はNG。 非推奨コードは使わない

こういったコードは思わぬバグが出てきてしまうこともしばしば…触らない方がバグやエラーを回避できます。wp_query_reset() はできれば使用せずに済ませたいものです。query_posts() 以外のリセットは wp_reset_postdata() を使用します。

サブループを使ったら wp_reset_postdata

サブループは主に WP_Query や get_posts で作成しますがこの時も取得した投稿情報をリセットする必要があります。
wp_reset_postdata()the_post()setup_postdata() を使用している場合に使います。

リセットする際、基本はこの wp_reset_postdata() を使うと覚えておいて問題ないでしょう。メインループの場合はリセットする必要がないので使いません。(そもそもリセットする行為がメインループに戻すためのものだからです)

ループが終わったタイミングでリセット

サブループを作ったら、最後に wp_reset_postdata() を使ってクエリをリセットします。記述はループが終わったところに。endwhile の後です。

<?php
  // 取得したい投稿内容
  $args = array(
    'post_type' => 'my_posts',
    'posts_per_page' => 3,
    'category' => '10',
    'no_found_rows' => true;
  );

  // オブジェクト取得
  $my_posts = new WP_Query($args);

  // ループの開始
  while ($my_posts->have_posts()):
    $my_posts->the_post();
?>
  <!-- 表示させたい投稿内容 -->
  <h1><?php the_title(); ?></h1>
  <div><?php the_content(); ?></div>

<!-- 投稿表示終了。メインクエリの値に戻す -->
<?php endwhile; wp_reset_post_data();?>

while文しかない場合は迷わずその後に書けるかと思いますが、<?php if(have_posts()): ?> を使った時はどうすればいいか悩んでしまうかもしれません。

if文をつけるパターンが多いので、他の記事では endif のところに書いているコードも多いです。間違いではありませんが、そこに書かなければならないということでもありません。

投稿がない場合に別のサブループを回すとき

if文の後に wp_reset_postdata() を書くようにしてしまうと困るのが「投稿がない場合別のサブループを回す」という場合です。

<?php if($my_posts->have_posts()): ?> // 指定した投稿がある場合
  <?php while($my_posts->have_posts()): $my_posts->the_post(); ?>
  // 投稿内容を繰り返し処理・表示
  <?php endwhile; wp_reset_postdata(); ?> // $my_postsのデータをリセット
  // 投稿内容の繰り返し処理が終わって一度のみ何かをしたいときはココ
<?php else: ?> // 投稿がなかったら
  <?php while($other_posts->have_posts()): $other_posts->the_post(); ?>
    // $my_postsとは別の投稿内容を表示
  <?php endwhile; wp_reset_postdata(); ?> // $other_postsのデータをリセット
<?php endif; ?>

こういった処理をしたい時にもif文の後にだけ書いてしまうと、その別のサブループはうまく取得できません。(その前に作ったループがまだ回っているからです)

「endif のところに wp_reset_postdata をつける」と思ってしまうと、こういった処理ができなくて進まなくなってしまうことも…
こういったことにも対応できるように、「while文の後にwp_reset_postdata()をつける」という風に覚えておいた方がいいと思います。

なぜリセットが必要?できるだけ使っておいた方がいい理由

サブループを使用した時というのは、投稿に関するグローバル変数を変更しています。($post, $id, etc..)このグローバル変数はシステム上で主要なものとして様々なところで使われるものです。

基本はメインクエリを使って様々な処理がされるため、リセットしないと、その後にメインクエリの内容を使って処理させるところに不具合、意図しないエラーが出ることも。

グローバルな領域への影響を最小限にとどめるた方が、思わぬエラーになりにくいと言えます。「リセットすると不具合がある」ということがなければ、メインクエリを使う使わないに関わらずリセットしておきましょう。

TOPへ