テンプレートに WP_Query を書いたのに、記事が1件も出ない。件数が合わない。2ページ目が404になる。投稿一覧のはずが固定ページの内容が出てしまう。WordPressのテーマ制作では、クエリまわりの「出ない」トラブルが頻繁に起こります。
原因は、実は数パターンに絞られます。この記事では、WP_Queryで記事が表示されないときに確認すべき7つのポイントを、切り分けやすい順に解説します。
まず基本形を確認する
切り分けの前に、正しい書き方の基本形を確認しておきます。
<?php
$args = array(
'post_type' => 'news',
'posts_per_page' => 5,
'post_status' => 'publish',
);
$query = new WP_Query( $args );
if ( $query->have_posts() ) :
while ( $query->have_posts() ) :
$query->the_post();
?>
<h2><?php the_title(); ?></h2>
<?php
endwhile;
endif;
wp_reset_postdata();
?>
ポイントは、ループの中では $query->have_posts() と $query->the_post() のように、変数に入れた自分のクエリを使うことと、最後に wp_reset_postdata() を呼ぶことです。これを踏まえて、原因を順に見ていきます。
ポイント1:post_typeの指定が間違っている
最も単純で、最も多い原因です。post_type を指定しないと、デフォルトの post(通常の投稿)だけが対象になります。カスタム投稿タイプの記事を出したいのに指定を忘れると、0件になります。
- カスタム投稿タイプの「スラッグ」と完全に一致しているか(大文字小文字、ハイフン、アンダースコア)
- 登録時の
register_post_typeの第1引数と同じ文字列か - 管理画面のURL(
edit.php?post_type=○○)で、正しいスラッグを確認する
日本語の「お知らせ」ではなく、あくまで登録時の英数字のスラッグを指定します。複数のタイプを対象にしたい場合は、配列で array( 'post', 'news' ) のように指定します。
ポイント2:post_statusと公開日時を確認する
WP_Queryは、デフォルトでは「公開済み」の記事だけを取得します。ログインしている場合は、非公開の記事も含まれることがあるため、ログイン中と未ログインで表示が違うという現象が起こります。
次の記事は、一覧に出ません。
- 下書き、承認待ち、非公開の記事
- 予約投稿(future)で、まだ公開日時が来ていない記事
- ゴミ箱に入っている記事
予約投稿の見落としは特に多く、「公開したはずなのに出ない」と思ったら、公開日時が未来になっていた、というケースがあります。管理画面の記事一覧で、ステータスと日時を確認してください。
ポイント3:pre_get_postsでクエリが書き換えられている
自分のWP_Queryには問題がないのに、アーカイブページなどで件数や並びがおかしい場合は、pre_get_posts フックによるメインクエリの書き換えが原因かもしれません。
functions.phpやmu-plugin、プラグインのどこかで、次のような処理が書かれていないか検索してみましょう。
add_action( 'pre_get_posts', function ( $query ) {
if ( ! is_admin() && $query->is_main_query() ) {
$query->set( 'posts_per_page', 3 );
}
} );
この例は、管理画面とメインクエリ以外は除外していますが、対象のページを絞っていないため、フロント側のすべての一覧が3件になります。書き換えが意図しないページにまで及ぶ場合は、is_home() や is_post_type_archive( 'news' ) のように、条件で対象を絞り込む必要があります。is_admin() と is_main_query() の判定が抜けていると、管理画面や、サブクエリにまで影響が出ます。
ポイント4:ページネーションが動かない
2ページ目以降を開いても、1ページ目と同じ内容が出る。このトラブルは、WP_Queryに paged を渡していないことが原因です。2ページ目以降が404になる場合は、メインクエリ側の投稿数や表示件数とずれていないかを確認してください(pre_get_postsで件数をそろえる方法は、次の記事で解説します)。
$paged = get_query_var( 'paged' ) ? get_query_var( 'paged' ) : 1;
$args = array(
'post_type' => 'news',
'posts_per_page' => 10,
'paged' => $paged,
);
$query = new WP_Query( $args );
注意したいのは、固定ページをフロントページに設定している場合です。この場合は paged ではなく page というクエリ変数が使われるため、get_query_var( 'page' ) を参照する必要があります。
また、ページ送りのリンクは、メインクエリの総ページ数をもとに出力されます。メインクエリが1ページ以下だと、the_posts_pagination() は何も出力しないため、サブクエリでは paginate_links() に、'total' => $query->max_num_pages と 'current' => max( 1, $paged ) を渡して出力します。
それでも404になる場合は、パーマリンク設定の再保存(設定 > パーマリンク設定で「変更を保存」)を試してください。リライトルールが更新され、直ることがあります。
ポイント5:wp_reset_postdata()を忘れている
サブクエリのループを使ったあと、wp_reset_postdata() を呼ばないと、グローバルな投稿データが書き換わったままになります。その結果、ループの後ろで使う the_title() や get_the_ID()、サイドバーの表示が、おかしくなります。
- ページの本来のタイトルではなく、サブクエリの最後の記事のタイトルが出る
- 後続のウィジェットやフッターで、別の記事の情報が表示される
サブクエリを使ったら、必ずループの直後に wp_reset_postdata() を呼ぶ。これは習慣にしておくと安心です。なお、query_posts() を使った場合は wp_reset_query() が必要ですが、そもそも query_posts() は使わないほうがよい関数です(詳しくは次回以降の記事で解説します)。
ポイント6:tax_query・meta_queryの条件が厳しすぎる
タクソノミーやカスタムフィールドで絞り込むと、条件の書き方ひとつで0件になります。
tax_queryでよくあるミス
fieldの指定(term_id、slug、name)と、termsに渡す値の種類が一致していない- スラッグの代わりに、日本語のタームの名前を渡している
- 複数の条件があるのに、
relationがANDのままで、同時に満たす記事がない
'tax_query' => array(
array(
'taxonomy' => 'news_cat',
'field' => 'slug',
'terms' => 'important',
),
),
meta_queryでよくあるミス
- キー名のスペルミス、大文字小文字の違い
- 数値を比較するのに、
typeをNUMERICにしていない(文字列として比較されて順序がずれる) - 日付の比較で、保存形式(Ymd か Y-m-d)と比較する値の形式が違う
- メタ値が存在しない記事は、条件によって除外される
原因の切り分けには、条件をひとつずつコメントアウトして、どの条件で0件になるか確認するのが確実です。
ポイント7:実際に発行されるSQLを確認する
ここまで確認しても原因が分からないときは、WP_Queryが実際に発行したSQLを見ましょう。
$query = new WP_Query( $args );
echo '<pre>' . esc_html( $query->request ) . '</pre>';
echo '見つかった件数:' . $query->found_posts;
request プロパティには、実際に実行されたSQLが入っています。WHERE句に、意図しない条件(post_type、post_status、タームの絞り込み)が入っていないか確認してください。「想定していたクエリ」と「実際のクエリ」の差が、原因そのものです。
デバッグ用の表示は、確認が終わったら必ず削除しましょう。本番サイトにSQLを出したままにするのは危険です。また、プラグイン「Query Monitor」を使うと、ページで実行されたクエリを管理バーから確認でき、開発中は大変便利です。
チェックリスト
記事が表示されないときは、次の順で確認してください。
- post_typeのスラッグは、登録時のものと一致しているか
- 記事のステータスと公開日時は、公開済みになっているか
- pre_get_postsで、クエリが書き換えられていないか
- pagedを渡しているか。パーマリンクを再保存したか
- wp_reset_postdata()を呼んでいるか
- tax_query・meta_queryの条件が厳しすぎないか
- $query->requestで、実際のSQLを確認したか
まとめ
WP_Queryで記事が出ない原因は、ほとんどが「指定の間違い」「条件の見落とし」「リセットの忘れ」のいずれかです。焦って全体を書き直す前に、上の7つを順番に確認すれば、たいていは数分で原因が見つかります。
とくに、post_typeのスラッグ、公開ステータス、pre_get_postsの影響は、見落としやすいポイントです。トラブルの際は、最後に実際のSQLを見て、想定との差を確かめる習慣をつけておきましょう。


コメント