
WordPressの投稿一覧を表示させるときにループを使いますが、そのループをリセットしたい時に使えるのが wp_reset_query()
と wp_reset_postdata()
です。この2つの使い方と違いについてのメモです。
なぜリセットが必要?できるだけ使っておいた方がいい理由
ループをリセットするというのは、メインクエリのデータに戻すということです。
WordPressでは、アクセスされたURLから投稿の一覧ページなのか詳細ページなのか、または固定ページなのかということを判別し、そのページタイプに必要なデータを取得します。このURLの判別によって取得される内容がメインクエリです。メインコンテンツの他、ヘッダーやサイドバーなど共通部分のどこかで常に使用されます。
メインループを使用している場合、そもそもリセットする行為がメインループに戻すことなので、リセットの必要はありません。
メインクエリのデータだと必要な投稿データが取得できない時には WP_Query
や get_posts
を使ってサブループを回します。この時にリセットが必要です。
サブループを使用した時は投稿に関するグローバル変数を変更しています。($wp_query, $post, etc..)このグローバル変数はシステム上で主要なものとして様々なところで使われるものです。
リセットしないと、その後にメインクエリの内容を使って処理されるべき場所で正しく動作しないことがあります。
グローバルな領域への影響を最小限にとどめるた方が、思わぬエラーになりにくいと言えます。リセットすると不具合がある、ということがなければリセットしておきましょう。
wp_reset_query と wp_reset_postdata の使い分け
この2つはリセットする変数が異なるので、どのコードを使ってループを回しているかによって使い分けられます。
- query_post を使ってのループなら wp_reset_query
- WP_Query や get_posts などを使ってのループなら wp_reset_postdata
query_post でループを回したら wp_reset_query
query_posts()
を使ってデータ取得をした場合、 wp_reset_query()
を使います。
wp_reset_query()
は以下のように定義されています。
function wp_reset_query() {
$GLOBALS['wp_query'] = $GLOBALS['wp_the_query'];
wp_reset_postdata();
}
wp_reset_query() | Function | WordPress Developer Resources
wp_reset_query()
は $wp_query
自体をリセットします。wp_the_query
というのはページを読み込んだ時に取得したデータのバックアップのようなものです。 $wp_query
(グローバル変数)の内容をそのバックアップしている内容に戻して、取得した投稿データもリセットします。
query_posts()
は $wp_query
を書き換えるコードです。$wp_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_reset_query()
は必要ありません。
新規でコードを書くなら query_posts は使わないようにする
wp_reset_query()
は query_posts()
を使用した場合に使うものですが、そもそも query_posts()
を使うのは非推奨とされています。
こういったコードは思わぬバグが出てきてしまうこともしばしば…触らない方がバグやエラーを回避できます。wp_query_reset()
は、できれば使用せずに済ませたいものです。
WP_Query や get_posts を使ったら wp_reset_postdata
WP_Query
や get_posts
を使ってデータ取得をした場合、wp_reset_postdata()
を使います。
wp_reset_postdata()
は以下のように定義されています。
function wp_reset_postdata() {
global $wp_query;
if ( isset( $wp_query ) ) {
$wp_query->reset_postdata();
}
}
「もし $wp_query
がセットされているなら $post
に入っている内容をリセットする」というものです。リセットする際、基本はこの wp_reset_postdata()
を使うと覚えておいて問題ないでしょう。
wp_reset_postdata() | Function | WordPress Developer Resources
WP_Query::reset_postdata() | Method | WordPress Developer Resources
ループが終わったタイミングでリセット
サブループを作ったら、最後に 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_postdata();?>
while文しかない場合は迷わずその後に書けるかと思いますが、<?php if(have_posts()): ?>
を使った時はどうすればいいか悩んでしまうかもしれません。
if文をつけるパターンが多いので、 endif; wp_reset_postdata();
と書いているコードも多いです。間違いではありませんが、そこに書かなければならないということではありません。あくまでendwhile(ループ終了)の後に記述していることがポイントです。
投稿がない場合に別のサブループを回すときは設定位置に注意
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文の後にだけ書いてしまうと、2つ目以降のサブループはうまく取得できません。
「endif のところに wp_reset_postdata をつける」と思ってしまうと、こういった処理ができなくて進まなくなってしまうことも…。
こういったことにも対応できるように、「while文の後に wp_reset_postdata()
をつける」という風に覚えておいた方がいいと思います。