本文へ移動

WP_Query高速化

WP_Queryで全件取得して大丈夫?posts_per_page=-1が重くなる理由と対策

WP_Queryで全件取得はできますが、公開ページではposts_per_page=-1を原則避けます。共通の安全件数はないため、件数の上限、実行頻度、ループ内の処理を確認し、件数制限やページ分割を先に検討します。

Huddly Huddly 投稿日: 2026年9月3日 読了目安: 3分

公開ページでは全件取得より件数制限を優先する

posts_per_page => -1は、条件に合う投稿をページ分割せず全件取得します。公開ページでは投稿が増えるたびに処理量も増えるため、まず「本当に全件を同時表示する必要があるか」を確認します。

公開一覧は件数制限、ページ分割、「もっと見る」を優先します。IDだけ必要ならfields => ‘ids’、大量処理なら分割を検討します。一方、件数が少なく上限も明確な設定用データや一時的な検証では、計測した上で使用を検討できます。

posts_per_page=-1はページ分割せず全件取得する

posts_per_pageは取得件数を指定する引数で、5なら最大5件です。-1を指定するとnopagingtrueになり、条件に合う投稿をページ分割せず取得します。

-1 は「最新1件」ではなく、「条件に合う投稿を全件取得する」方向の指定です。

今の投稿数で動くことと、運用後も負荷を抑えられることは別です。公開ページで毎回全件を取ると、投稿数が増えた後に問題が表れます。

全件取得が重くなりやすい理由

取得件数以外も含めて負荷を見直したい場合には、WP_Queryを高速化する7つの方法もご覧ください。件数や総ページ数が合わない場合は、速度対策を施す前に表示件数が合わない時の確認事項を確認してください。

全件取得では、データベースから取る量、PHPが保持・処理する量、生成するHTMLが同時に増えます。

100件では問題が目立たなくても、1,000件、5,000件と増えるにつれて、同じコードでも負荷は大きくなります。
重くなる処理何が増えるか起きやすい問題
データベース取得条件に合う投稿の読み込み量クエリの実行時間が伸びる
PHP処理投稿オブジェクトや関連データの扱いメモリ使用量が増える
テンプレート表示ループ内の出力回数HTML生成やテンプレートタグ呼び出しが増える
ブラウザ表示ページ内のDOMやリンク数ユーザー側でも表示が重くなる

さらに、カスタムフィールドやタクソノミー条件を組み合わせている場合は、条件そのものも複雑になりやすくなります。meta_querytax_query が悪いわけではありませんが、全件取得と組み合わさると、確認すべき範囲が一気に広がります。

公開ページで避けたい全件取得の書き方

次は、公開ページで全記事を一度に取得する例です。少数の検証データでは問題が見えにくい点に注意してください。

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

PHParchive-example.php公開ページで全記事を一度に取得してしまう例
$args = [   'post_type'      => 'post',   'post_status'    => 'publish',   'posts_per_page' => -1,]; $all_posts = new WP_Query( $args ); if ( $all_posts->have_posts() ) {   echo '<ul>';    while ( $all_posts->have_posts() ) {      $all_posts->the_post();       printf(         '<li><a href="%1$s">%2$s</a></li>',         esc_url( get_permalink() ),         esc_html( get_the_title() )      );   }    echo '</ul>';} else {   echo '<p>表示できる投稿はありませんでした。</p>';} wp_reset_postdata();

この例が危険なのは、投稿数に上限を設けず、アクセスのたびに全件を取得して全件分のHTMLを作るためです。実際のテンプレートでは、画像、抜粋、カスタムフィールド、タームなどの処理も全件分繰り返します。件数だけでなく、ループ内の追加取得や出力量も確認します。

posts_per_page=-1を検討できる場面

posts_per_page => -1は常に禁止ではありません。対象件数に予測可能な上限があるか、表示か処理か、実行頻度を管理できるかで判断します。

「何件までなら大丈夫」という共通の上限はありません。投稿の大きさ、ループ内の処理、アクセス数、サーバー環境によって負荷が変わるためです。対象が少なく上限も予測できる設定用データ、一時的な管理・検証処理などでは使用を検討できます。逆に、投稿、商品、イベント、会員向けコンテンツのように増え続けるデータでは慎重に扱います。

場面判断理由
公開ページの記事一覧原則避けるアクセスのたびに全件処理されやすい
トップページの新着枠避ける必要なのは数件だけのことが多い
サイトマップ風の小規模一覧件数次第で検討対象が少なく上限を予測できる場合がある
管理画面や一時的な検証使える場合がある公開ページより実行頻度を管理しやすい
バッチ処理や移行処理一括取得を前提にしない一定件数ずつの分割やWP-CLIを検討する

公開一覧なら、最新10件、カテゴリごとに20件、ページ分割など、読者が必要な範囲へ絞れないかを先に考えます。

全件取得の代わりに選びたい書き方

公開ページでは必要な件数を明示し、残りはページ分割や「もっと見る」で辿れるようにします。次は最新記事を10件だけ取得する例です。

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

PHPlatest-posts.php公開ページで取得件数を制限する例
$args = [   'post_type'           => 'post',   'post_status'         => 'publish',   'posts_per_page'      => 10,   'ignore_sticky_posts' => true,]; $latest_posts = new WP_Query( $args ); if ( $latest_posts->have_posts() ) {   echo '<ul>';    while ( $latest_posts->have_posts() ) {      $latest_posts->the_post();       printf(         '<li><a href="%1$s">%2$s</a></li>',         esc_url( get_permalink() ),         esc_html( get_the_title() )      );   }    echo '</ul>';} else {   echo '<p>表示できる投稿はありませんでした。</p>';} wp_reset_postdata();

ignore_sticky_postsは、固定表示投稿の影響を受けたくない独自一覧で検討します。

ページ分割が必要な一覧では、paged と組み合わせて「1ページあたり何件表示するか」を決めます。全件を1ページに詰め込むのではなく、ページごとに分けて取得する考え方です。

posts_per_page => -1はページ分割しない指定です。pagedを追加しても「全件取得しながらページ分割」にはなりません。

ページ送りが必要なら、posts_per_pageへ1ページの件数を指定してください。

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

PHPpaged-posts.phpページ分割を前提に件数を制限する例
$paged = max( 1, get_query_var( 'paged' ) ); $args = [   'post_type'      => 'post',   'post_status'    => 'publish',   'posts_per_page' => 10,   'paged'          => $paged,]; $paged_posts = new WP_Query( $args );

posts_per_pageで1ページの件数を決め、pagedで現在のページ番号を渡します。全件取得後に分けるのではなく、必要なページ分だけ取得します。

IDだけ必要ならfieldsを検討する

後続処理で投稿IDだけを使う場合は、fields => ‘ids’で投稿IDの配列を取得できます。

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

PHPpost-ids.php投稿IDだけを取得する例
$args = [   'post_type'      => 'post',   'post_status'    => 'publish',   'posts_per_page' => 100,   'fields'         => 'ids',   'no_found_rows'  => true,]; $id_query = new WP_Query( $args );$post_ids = $id_query->posts;

取得したIDは$id_query->postsに入ります。no_found_rows => trueは、ページ数や総件数が不要な処理で使います。

ただし、fields => ‘ids’no_found_rows => trueを付ければ、無制限に取得してよいわけではありません。IDだけであっても、対象が数万件になれば処理量は増えます。大量データを扱うなら、一定件数ごとに分け、処理時間とメモリ使用量を計測してください。

全件取得する前に確認したい順番

表示目的と処理目的を分けて、次の順に判断します。

posts_per_page=-1を書く前の確認順

  1. 1
    本当に全件を画面に表示する必要があるか確認する
  2. 2
    表示目的なら10件や20件に制限できないか考える
  3. 3
    一覧が長いならページ分割やもっと見る導線を検討する
  4. 4
    IDだけで足りる処理ならfieldsを検討する
  5. 5
    大量処理なら一度に処理せず分割実行を考える

最後は推測ではなく計測します。クエリ時間とメモリだけでなく、ループ内で投稿ごとに追加取得が起きていないか、生成されるHTML量や表示時間が増えていないかも確認してください。

公式資料で確認したいポイント

-1no_found_rowsfieldsはWP_Queryの公式資料で確認できます。通常のループでthe_post()を使ったら、後続のテンプレートタグを戻すためwp_reset_postdata()も必要です。

公式リンク

公式ドキュメント

最後に確認したいこと

  • posts_per_page=-1が全件取得方向の指定だと理解している
  • 公開ページで本当に全件表示が必要か確認した
  • 件数制限やページ分割を先に検討した
  • IDだけ必要な処理ではfieldsを検討した
  • 大量データでは一括処理ではなく分割処理を考えた
WP Query BuilderBuilderで条件を組み直す条件を選び、WP_Queryのコードを画面で作れます。Builderでクエリを作る

この記事を書いた人

Huddly

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

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

この記事の検証情報

検証環境

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

更新履歴

  • 2026年9月3日 初回公開

この記事を活用する

あとで見返す・共有する

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

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