本文へ移動

WP_Query解説

query_postsを使わないほうがいい理由
|WP_Query・pre_get_postsとの違い

テーマを編集していてquery_posts()を見つけたら、そのまま真似せず「現在の投稿一覧を変えるコードか、別の一覧を追加するコードか」を確認します。メイン一覧ならpre_get_posts、記事下やサイドバーの別一覧ならWP_Queryまたはget_posts()が基本です。

Huddly Huddly 投稿日: 2026年8月28日 更新日: 2026年9月12日 読了目安: 6分

query_postsを見つけたら、用途に合う方法へ置き換える

query_posts()は、別の投稿一覧を追加するための普通の取得関数ではなく、メインループが参照するグローバルなクエリを別のクエリへ差し替える関数です。WordPress公式も、テーマやプラグインではできる限り避けるよう案内しています。

投稿一覧やアーカイブのメイン一覧を変えるならpre_get_posts、記事下などに別一覧を足すならWP_Queryまたはget_posts()が基本です。まず古いコードがどちらを変えているかを確認し、用途に合う方法へ置き換えます。

まず、どの一覧を変えるコードか確認する

古いテーマや検索で見つけたコードでは、一覧件数を変えるためにquery_posts()が使われていることがあります。最初に、そのコードが投稿一覧やアーカイブのメイン一覧を変えているのか、記事下やサイドバーに別一覧を足しているのかを確認します。

公式リファレンスは、query_posts()がメインクエリを完全に上書きするため、テーマやプラグインでは避けるよう案内しています。

問題になりやすい点何が起きるか代わりに考えるもの
メインクエリを置き換える現在のページ用に用意された取得条件を後から差し替えてしまうpre_get_posts
ページネーションが崩れやすいpagedなどを自分で考慮しないとページ送りが合わないpre_get_posts
追加のSQLが発生しやすいすでに取得された結果を捨てて、もう一度取得する形になりやすいpre_get_posts
別一覧との区別がつきにくいメイン一覧なのか追加一覧なのかコードから読みづらいWP_Query / get_posts

先に、現在のページの一覧を変えたいのか、別枠の一覧を足したいのかを分けます。

投稿一覧やアーカイブの表示件数を変えるならメインクエリ、記事下に新着3件を足すなら別クエリです。同じ「一覧」でも、置き換え先はここで決まります。 query_posts()の問題は、投稿を取得できるかどうかではなく、WordPressが持っている現在のページの文脈を後から置き換えてしまう点です。

メインクエリを後から差し替えると分かりにくくなる

メインクエリと追加のWP_Queryの違いはWP_Queryの役割と使い方で先に整理できます。別ループを作った後の後処理はwp_reset_postdata()が必要な理由へ続けてください。

WordPressはURL、表示設定、カテゴリー、検索語などからメインクエリを先に作ります。query_posts()はテンプレートまで来てからそれを置き換えるため、元のアーカイブ条件やページの文脈が追いにくくなります。

次は古いhome.phpのメインループ前で見かける形です。投稿一覧の件数を変える意図でも、テンプレートから参照先のクエリを置き換えています。避けたい例として示すもので、新しく貼って使うコードではありません。

クラシックテーマのテンプレート(またはテンプレートパーツ)で、一覧を表示したい位置に置く例です。投稿本文やfunctions.phpへ、そのまま貼るコードではありません。

PHPhome.php採用しない例:query_postsで投稿一覧のクエリを後から差し替える
<?phpquery_posts( [   'posts_per_page' => 5,] ); if ( have_posts() ) {   echo '<ul>';    while ( have_posts() ) {      the_post();       printf(         '<li><a href="%s">%s</a>(ID: %d)</li>',         esc_url( get_permalink() ),         esc_html( get_the_title() ),         get_the_ID()      );   }    echo '</ul>';} wp_reset_query();

最後にwp_reset_query()を書いても、既に実行されたメインクエリとは別に再取得し、置き換える構造は変わりません。ページ送りではpagedも考慮する必要があります。

内部ではグローバルな$wp_queryが差し替わり、元のメインクエリは$wp_the_queryに残ります。wp_reset_query()は参照先を元へ戻しますが、その前に表示した一覧や、失われたページ番号をさかのぼって直すものではありません。単にリセット関数を追加するだけでは、置き換えの解決になりません。

メインクエリを変えたいならpre_get_postsを使う

メイン一覧を変えるなら、pre_get_postsで実行前のクエリ条件を調整します。

たとえば投稿一覧ページのposts_per_pageを5にしたい場合は、古いquery_posts()とそれ専用のwp_reset_query()を外し、クラシック子テーマのfunctions.phpのPHP領域へ次の関数と登録処理を1回だけ追加します。すでにPHPが始まっている場所へ<?phpを重ねて貼らないでください。通常のメインループとテーマのページ送りは残します。

WP Query Builderが生成するのは、新しく作るWP_Queryへ渡す$argsです。すでにWordPressが組み立てたメインクエリを変更するpre_get_postsのフックや、管理画面・メインクエリ・feedを除外する条件分岐は生成しません。次は、その境界を含めて手動で実装するコードです。

子テーマのfunctions.phpまたは機能プラグインに置く例です。対象画面と実行条件を確認し、検証環境で試してから本番へ反映してください。

PHPfunctions.php投稿一覧ページのメインクエリをpre_get_postsで調整する例
<?phpfunction wpq_limit_home_posts( $query ) {   if ( is_admin() || ! $query->is_main_query() || $query->is_feed() ) {      return;   }    if ( $query->is_home() ) {      $query->set( 'posts_per_page', 5 );   }}add_action( 'pre_get_posts', 'wpq_limit_home_posts' );

$query->is_main_query()でメインクエリだけを対象にし、is_admin()で管理画面、$query->is_feed()でフィードを除外しています。この関数自体は記事を出力せず、既存の投稿一覧が取得する件数だけを変えます。

pre_get_postsは「どの画面の、どのクエリを変えるか」まで限定して初めて安全に使えます。posts_per_pageだけを合わせて、対象判定を省かないでください。

ここでのis_home()は「投稿一覧ページ」を指し、固定フロントページと常に同じではありません。管理画面の「ホームページの表示」によって対象URLが変わるため、フロントページだけを変えたい場合は要件と条件分岐を見直してください。pre_get_postsの条件を広く書きすぎると、アーカイブや検索結果、feedまで変わることがあります。

同じ投稿一覧のページ2で表示を比べる

公開済みの通常投稿23件がある投稿一覧を使い、paged=2で表示します。古い例は5件という条件だけでクエリを作り直すため、元のページ番号を引き継ぎません。pre_get_postsの例は既存クエリの件数だけを変更するので、ページ2という条件が残ります。

次の画像で比べるのは「何件出たか」だけではありません。URLはどちらもページ2のままなのに、旧例はpaged=0の別クエリへ差し替わり、置換後はpaged=2を保っている点が判断材料です。
投稿一覧のページ2でquery_postsを使い、ID13・82・81・80・79・15が表示されるサイト
避けたい例の結果ページ2なのに、先頭側の記事へ戻る

query_posts後のpagedは0。固定投稿ID13の先頭追加も働き、ID13・82・81・80・79・15の6件が出ています。

pre_get_postsで件数だけを変更し、ページ2のID14・13・12・11・10が表示されるサイト
pre_get_postsへ置き換えページ2の条件を残して5件を表示

メインクエリのposts_per_pageだけを5へ変更。paged=2を保ち、ID14・13・12・11・10を取得しています。

この比較では固定投稿ID13の設定を残しています。1ページ目では先頭へ追加されて6件になる一方、2ページ目では日付順の本来の位置にも出ます。固定投稿の追加や再登場は、ページ番号が失われる問題とは別です。常に通常の日付順・5件へ揃えたい場合は、ignore_sticky_postsの方針も表示件数の確認で整理してください。

query_posts()の例は、表示後のwp_reset_query()によって元のクエリへ戻りましたが、出力済みの6件はそのままです。pre_get_postsの例ではクエリの参照先を差し替えず、カテゴリー・検索・フィード・別の3件取得にはこの件数変更を適用しません。

古いクエリの置き換えは、本番と分けた環境で1ページ目・2ページ目を確認します。サーバー上でも試す場所が必要なら、XserverのPHP対応やバックアップ条件を確認できます。

別の一覧を追加したいならWP_Queryかget_postsを使う

関連記事やサイドバーの新着など、別枠の一覧ならWP_Queryかget_posts()を使います。メインクエリを変える必要はありません。

やりたいこと選びやすい方法理由
投稿一覧やアーカイブのメイン一覧を変えたいpre_get_postsメインクエリが実行される前に対象を限定して調整できる
記事下に関連記事を追加したいWP_Query独立したqueryとしてページ送りや状態を扱える
少量の投稿配列を取得したいget_posts()既定では5件で、総ページ数を使わない小さな取得に向く
古いコードでquery_postsを見つけた目的を確認して置き換えるメイン一覧か追加一覧かで正しい代替が変わる

get_posts()はWP_Queryの単なる高速版ではありません。少量の投稿配列を受け取る用途に向き、既定の取得件数は5件です。取得後にsetup_postdata()を使ってテンプレートタグの参照先を切り替えた場合は、最後にwp_reset_postdata()が必要です。

次は通常投稿の個別ページで、現在の記事を除外し、新着3件を別クエリで表示する例です。クラシック子テーマのtemplate-parts/recent-posts.phpへ保存し、single.phpなどのメインループ内でthe_post()と本文表示の後にget_template_part( ‘template-parts/recent-posts’ );を呼びます。カテゴリーのアーカイブにそのまま流用しないでください。

現在のWP Query Builderでは、詳細設定で「post / publish / 3」、orderに「DESC」、orderbyに「date」、post__not_inに検証ページの投稿ID「15」、ignore_sticky_postsにtrueを入力しました。自動高速化はオフです。次の$argsは、その実画面で生成された内容を変更せずに載せています。

クラシックテーマのテンプレート(またはテンプレートパーツ)で、一覧を表示したい位置に置く例です。投稿本文やfunctions.phpへ、そのまま貼るコードではありません。

PHPtemplate-parts/recent-posts.php現在の通常投稿を除外して新着3件を別のWP_Queryで表示する
<?php$current_post_id = get_queried_object_id(); $args = array(   'post_type' => 'post',   'post_status' => 'publish',   'posts_per_page' => 3,   'order' => 'DESC',   'orderby' => 'date',   'post__not_in' => array(      15   ),   'ignore_sticky_posts' => true); $args['post__not_in'] = array( $current_post_id );$related_query = new WP_Query( $args ); if ( $related_query->have_posts() ) {   echo '<ul>';    while ( $related_query->have_posts() ) {      $related_query->the_post();       printf(         '<li><a href="%s">%s</a>(ID: %d)</li>',         esc_url( get_permalink() ),         esc_html( get_the_title() ),         get_the_ID()      );   }    echo '</ul>';} else {   echo '<p>表示できる投稿はありませんでした。</p>';} wp_reset_postdata();

Builderが生成したのは$argsまでです。$current_post_idの取得とpost__not_inを現在の記事IDへ置き換える1行、new WP_Query()、リンクと投稿IDの表示、0件時の文言、wp_reset_postdata()は手動で追加しています。検証ページでは現在の記事もID15なので、置き換え前後の除外値は同じです。本番では表示中の記事IDに変わります。

$related_queryだけを回し、the_post()を使った後はwp_reset_postdata()で投稿データを戻します。同じ公開日時の投稿同士まで順番を固定したい場合は、Builder生成後にorderbyへIDの第2条件を加える設計が別途必要です。この例と画像は、公開日が異なる検証投稿を使っています。

Builderの固定値15は実画面と検証結果を再現する入力です。再利用時は、その値を残すのではなく、直後の手動行で現在の記事IDへ置き換えます。

通常投稿ID15の本文後でこのコードを動かすと、別一覧はID82・81・80の3件になり、処理後のget_the_ID()は15へ戻ります。メインクエリの参照先も変わりません。対象の投稿タイプに公開投稿がなければ、0件メッセージを出した後もID15のままです。

この例は新着一覧であり、同じカテゴリーやタグで関連記事を選ぶ条件までは含みません。確認用として追加した場合は、呼び出しとファイルを撤去します。関数側の例を外す場合も、関数定義と対応するadd_action()をセットで戻してください。

置き換え後に戻す時も、functions.phpの関数だけ、またはadd_action()だけを残さないでください。別一覧はテンプレートパーツと呼び出し側を対で管理します。

追加一覧をWP_Queryへ置き換えると決めたら、WP Query Builderでその取得条件を整理できます。生成した$argsを別一覧の表示ループへ渡し、元の記事の参照先が戻ることまで確かめます。

置き換え後のWP_Query条件を作る

別一覧用のpost_type、件数、絞り込み、並び順から$argsを作れます。pre_get_postsの条件分岐、ページネーション、リセット位置はテンプレート側で確認してください。

古いquery_postsコードを見つけた時の置き換え方

古いコードは機械置換せず、メインループ直前なのか、記事下やサイドバーの小さな一覧なのかを確認します。

query_postsを見つけた時の確認順

  1. 1
    そのコードがメイン一覧を変えているのか、追加一覧を作っているのか確認する
  2. 2
    メイン一覧ならpre_get_posts、追加一覧ならWP_Queryまたはget_posts()を候補にする
  3. 3
    query vars、URL条件、ページネーションを保ったまま置き換える
  4. 4
    1ページ目と2ページ目、archive、search、404、feedで回帰確認する

query_posts()と一緒にあるwp_reset_query()も、WP_Queryのループへ変えた場合はwp_reset_postdata()へ変わることがあります。取得方法と後処理をセットで見直してください。

query_posts()の注意点と代替手段の公式資料

公式資料でquery_posts()の注意、pre_get_postsの対象限定、WP_Queryとget_posts()の違いを確認できます。

公式リンク

公式ドキュメント

最後に確認したいこと

  • query_postsはメインクエリを置き換える関数だと理解している
  • メイン一覧を変えるならpre_get_postsを検討できる
  • 別一覧を作るならWP_Queryまたはget_postsを検討できる
  • query_postsを見つけた時に目的を確認してから置き換え先を選べる
  • WP_Queryの別ループ後にwp_reset_postdata()を置いた
WP Query BuilderBuilderで条件を組み直す条件を選び、WP_Queryのコードを画面で作れます。Builderでクエリを作る

この記事を書いた人

Huddly

Web制作 / フロントエンドエンジニア

WordPressとフロントエンド実装で迷いやすい点を、公式情報と検証結果を分けながら、初学者にも追いやすい順序で整理しています。

この記事の検証情報

検証環境

WordPress
7.1.4
PHP
8.3.36
テーマ
wpq-media + DDEV
対象
カスタム投稿 / taxonomy / meta_query

更新履歴

  • 2026年9月12日 本文と補助情報を更新
  • 2026年8月28日 初回公開

この記事を活用する

あとで見返す・共有する

お気に入りに保存できます。役に立ったポイントは、いいねや共有で教えてください。

任意のご支援 役に立ったときだけ、活動を応援できます OFUSEはサイト・記事制作に使います。支援の有無で、読める内容や使える機能は変わりません。