本文へ移動

WP_Query基礎

WordPressの投稿一覧はどう作る?
|4つの方法とWP_Queryの使い分け

WordPressで投稿一覧を作る方法は1つではありません。今ある一覧を変えるのか、別の一覧を追加するのかを決めたうえで、コードの要否と取得後に使いたい情報から選びます。

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

追加する一覧か、今ある一覧かで選びます

固定ページや記事下へ別の投稿一覧を追加するなら、まずコード不要のQuery Loopを検討します。PHPが必要でも、数件を配列で受け取るだけならget_posts()、独自のループ・総件数・ページ数まで扱うならWP_Queryが候補です。

カテゴリー、検索、投稿タイプアーカイブなど、WordPressが用意した一覧の取得条件をPHPで変えるなら、pre_get_postsでメインクエリを対象にします。まず「今ある一覧を変えたいのか、もう1つ足したいのか」から考えてみましょう。

3つの質問から使う方法を絞る

作りたい一覧が思い浮かんでも、いきなり関数名から選ぶのは難しいものです。まずは置く場所と表示したいものを決め、次の質問を上から見てみましょう。候補が決まったら、その方法の説明へ進めます。

1. WordPressが用意した一覧の取得条件を変えたい?

はいなら、カテゴリーや検索などのメインクエリを変更するpre_get_postsが候補です。いいえで、ページの中へもう1つ一覧を追加したいなら、質問2へ進みます。なお、サイト全体の表示件数を変えるだけなら、WordPressの表示設定で足りる場合もあります。

2. エディターの設定だけで、必要な条件と見た目を作れる?

はいなら、Query Loopを選べます。いいえで、PHPを使った処理が必要なら質問3へ進みます。たとえば独自のカスタムフィールド条件や、取得後のデータ処理が必要な場合です。

3. 投稿やIDの配列だけを受け取れれば足りる?

はいなら、get_posts()が候補です。いいえで、テンプレートタグを使うループ、総件数、総ページ数まで扱いたいならWP_Queryを選びます。数件の表示でも、ループで書く方が分かりやすければWP_Queryで構いません。

実際の要望に当てはめると、次のように選べます。

今やりたいこと第一候補選ぶ理由
固定ページへコードなしで記事一覧を置くQuery Loopエディターで取得条件、繰り返す表示、ページ送りを組み立てられる
テンプレート内で最新記事を3件だけ取得するget_posts()必要な数件を配列で受け取り、foreachで扱いやすい
記事の下へ独自の条件で関連記事を出し、ループやページ情報も使うWP_Queryオブジェクトに結果、総件数、総ページ数、ループの状態を持てる
カテゴリー一覧の表示件数を変えるpre_get_postsWordPressが実行するメインクエリを取得前に調整できる
同じ「記事一覧」でも、今ある一覧を変更する処理と、別の一覧を追加する処理は分けて考えます。

4つの方法を変更対象・返り値・ページ送りで比べる

WP_Queryとget_posts()は、どちらも投稿を新たに取得できます。pre_get_postsは投稿一覧を返す関数ではなく、実行前のクエリを変更するフックです。Query Loopは、投稿の取得と繰り返す見た目をエディター上で組み合わせるブロックです。表の「受け取るもの」は、処理後にコードや画面で使える結果を表しています。

方法主な変更対象受け取るものページ送り主な置き場所
Query Loopページ内へ追加する一覧ブロックが表示まで担当ページ送りブロックを追加できる投稿・固定ページ・ブロックテンプレートのエディター
get_posts()追加で使う数件の投稿WP_PostまたはIDの配列総件数・総ページ数の利用には向かないPHPテンプレート、関数、プラグイン
WP_Query追加で取得する投稿WP_Queryオブジェクトfound_postsとmax_num_pagesを扱えるPHPテンプレート、テンプレートパーツ、プラグイン
pre_get_postsこれから実行するクエリ渡されたWP_Queryを変更メインクエリのページ送りと合わせて調整しやすいfunctions.phpまたはサイト固有プラグイン

Query Loopはブロックテンプレートで元のクエリを引き継ぐ使い方もできます。ここではページ内へ別の一覧を追加する場面を比べているため、表の説明をその用途へ絞っています。

コードの見た目も短く並べてみます。次は違いを読むための抜粋です。4つをまとめて貼り付ける完成コードではありません。 Query LoopはPHPの関数ではないため、エディターで行う設定をコメントで示しています。

引数や処理の一部分だけを示した例です。このまま単独で貼らず、テンプレート内のWP_Queryとループへ組み込んでください。

PHPcomparison-excerpt.php4方式で記述する内容の違いを読むための抜粋
// Query Loop:エディターで投稿タイプ・件数3・表示するブロックを設定。 // get_posts():配列を受け取る。表示は別に書く。$posts = get_posts( [ 'posts_per_page' => 3 ] ); // WP_Query:オブジェクトを作る。表示ループは別に書く。$query = new WP_Query( [ 'posts_per_page' => 3 ] ); // pre_get_posts:これから実行するカテゴリーのメインクエリを変える。add_action( 'pre_get_posts', function ( WP_Query $query ) {   if ( ! is_admin() && $query->is_main_query() && $query->is_category() ) {      $query->set( 'posts_per_page', 3 );   }} );

get_posts()とWP_Queryは取得部分だけならどちらも短く書けますが、受け取るものは配列とオブジェクトで異なります。pre_get_postsは条件を変える処理を先に登録する書き方です。行数より、取得した後に何を使いたいかで選ぶと迷いにくくなります。実際に置く場所と表示まで含めた例は、この先で分けて説明します。

Query Loopはコードを書かずに一覧を追加したいときに使う

固定ページへ新着記事、特定カテゴリーの記事、ポートフォリオなどを置きたい場合は、まずQuery Loopで作れるか確認します。Query Loopの内側にはPost Templateがあり、その中へタイトル、アイキャッチ、抜粋、日付などを配置します。必要ならPaginationとNo Resultsも追加できます。

Query Loopが向いているのは、編集者がエディターで取得条件と見た目を管理したい場合です。テーマやWordPressが用意する設定の範囲で要件を満たせるなら、PHPファイルを編集する必要はありません。

現在のQuery Loopには、表示中の記事を除外する設定もあります。まずエディターの設定で足りるか確かめてみましょう。複数の独自の値を複雑な条件で組み合わせる、取得した投稿IDをほかの処理へ渡すなど、画面設定だけでは表現できない要件があるときにPHP側の方法を検討します。

get_postsは少数の投稿を配列で受け取りたいときに使う

get_posts()は、条件に合う投稿をWP_Postの配列として受け取ります。WordPress公式も、小さく単純なパラメーターで投稿配列を取得する用途を適切な場面として説明しています。

次の例は、検証環境のカテゴリー「お知らせ」(ID 2)に属する公開投稿を、新しい順に3件取得します。後のコード・表・画像も同じカテゴリーを使います。ご自身の環境ではcatのIDを置き換え、カテゴリーで絞らない場合はこの行を外してください。

子テーマのtemplate-parts/latest-posts.phpへ保存し、single.phpのメインループでthe_post()を呼んだ後にget_template_part( ‘template-parts/latest-posts’ );を1回記述すると、その場所へ一覧を追加できます。クラシックテーマで、パーツの保存と呼び出しを組み合わせる例です。

新規のPHPファイルなら先頭に<?phpを置き、既存のPHP内へ追加するときは開始タグを重ねません。呼び出す側の1行もPHPの内側へ記述します。各WP_Postを関数へ直接渡すので、テンプレートタグが参照する投稿データは切り替わりません。

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

PHPtemplate-parts/latest-posts.php最新3件をWP_Postの配列として表示する
$latest_posts = get_posts(   [      'post_type'      => 'post',      'post_status'    => 'publish',      'posts_per_page' => 3,      'cat'            => 2,      'orderby'        => 'date',      'order'          => 'DESC',   ]); if ( $latest_posts ) {   echo '<ul>';    foreach ( $latest_posts as $latest_post ) {      printf(         '<li><a href="%1$s">%2$s</a></li>',         esc_url( get_permalink( $latest_post ) ),         esc_html( get_the_title( $latest_post ) )      );   }    echo '</ul>';}

get_posts()は内部でWP_Queryを使いますが、返すのはクエリオブジェクトではなく投稿またはIDの配列です。また、ignore_sticky_postsとno_found_rowsは関数内でtrueに設定されます。総件数や総ページ数を使う一覧より、取得した数件をそのまま利用する処理に向いています。

この例はsetup_postdata()を使わないため、リセットも不要です。配列の中身と既定値の違いはget_postsとWP_Queryの比較で詳しく説明しています。

投稿の取得コードを試すときは、本番と分けたWordPress環境で、件数と表示順が意図どおりか見ておくと安心です。検証や公開に使うサーバーをこれから用意する場合は、XserverのPHP対応やバックアップ条件も確認できます。

WP_Queryは独自ループとクエリ情報が必要なときに使う

WP_Queryは投稿取得を扱うクラスです。new WP_Query( $args )で作るオブジェクトは、取得した投稿だけでなく、取得件数、条件に合う総件数、総ページ数、ループの現在位置も持ちます。ループで表示したり、ページ送りを作ったりしたいときに役立ちます。

次は同じカテゴリーの最新3件を表示する別の実装です。最初のパーツを丸ごと置き換えて比べます。両方を残すと一覧が2回表示されるため、比較後は使う方だけ残してください。

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

PHPtemplate-parts/latest-posts.php独自のWP_Queryで最新3件を表示する
$latest_query = new WP_Query(   [      'ignore_sticky_posts' => true,      'post_type'      => 'post',      'post_status'    => 'publish',      'posts_per_page' => 3,      'cat'            => 2,      'orderby'        => 'date',      'order'          => 'DESC',   ]); if ( $latest_query->have_posts() ) {   echo '<ul>';    while ( $latest_query->have_posts() ) {      $latest_query->the_post();       printf(         '<li><a href="%1$s">%2$s</a></li>',         esc_url( get_permalink() ),         esc_html( get_the_title() )      );   }    echo '</ul>';} wp_reset_postdata();

$latest_query->have_posts()で次の投稿があるかを確かめ、$latest_query->the_post()でその投稿へ進みます。どちらも$latest_query->から始めることで、今回取得した同じクエリの結果を使っています。先頭固定投稿の優先はignore_sticky_posts=trueで無効にし、前のget_posts例と揃えています。

the_post()はテンプレートタグが参照する投稿データを一時的に切り替えます。ここではメインループから呼び出しているので、終了後にwp_reset_postdata()でメインループの投稿へ戻します。追加した別のループへ入れ子にする場合は、戻す対象が異なる点に注意が必要です。リセットの説明も参考にしてください。

カテゴリーや検索のテンプレート内でnew WP_Query()を作っても、元の一覧を取得するメインクエリは変わりません。今ある一覧そのものの条件を変えたい場合は、次のpre_get_postsを検討します。

WP_Queryを使う方法に決めたら、WP Query Builderで取得条件を組み立ててみましょう。今回のカテゴリー・3件・日付降順から始め、生成した$argsと表示コードを合わせて試せます。

使いたい投稿の条件を形にする

投稿タイプ・絞り込み・並び順・件数を画面で選べます。生成されたコードと説明を見比べ、設置場所やリセットはこの記事の例と合わせて実装します。

pre_get_postsは既存のメイン一覧を取得前に変えるときに使う

カテゴリー、タグ、検索結果、投稿タイプアーカイブなどは、WordPressがURLに合わせてメインクエリを準備します。この一覧の表示件数や対象投稿を変えるために、同じ一覧をnew WP_Query()で作り直す必要はありません。

pre_get_postsは、投稿を取得する前に処理を挟むためのアクションフックです。add_action()で関数を登録しておくと、WordPressがクエリを実行する前に呼び出します。

次の例は、公開側のカテゴリー一覧だけ表示件数を6件へ変えます。子テーマのfunctions.phpなど、クエリの実行前に読み込まれる場所のPHP開始タグの内側へ、関数とadd_action()をまとめて1回登録してください。比較用抜粋の3件設定とは併用しません。wptl_はサンプルの接頭辞なので、名前を変える場合はadd_action()の登録名も揃えます。

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

PHPfunctions.phpカテゴリーのメイン一覧を1ページ6件へ変更する
function wptl_change_category_posts_per_page( WP_Query $query ) {   if ( is_admin() || ! $query->is_main_query() ) {      return;   }    if ( $query->is_category() ) {      $query->set( 'posts_per_page', 6 );   }}add_action( 'pre_get_posts', 'wptl_change_category_posts_per_page' );
pre_get_postsはメイン以外のクエリでも動きます。管理画面・メインクエリ・変更したいページの3点を確認してから、値を変えます。

この例では、is_admin()で管理画面を除外し、$query->is_main_query()でメインを選び、$query->is_category()でカテゴリー一覧に絞っています。検索や特定アーカイブを変える場合も、そのページに合う条件が必要です。

固定ページ1件を取得するメインクエリを、無理に投稿一覧へ変える用途には向きません。公式資料にも、単一ページとアーカイブのようにクエリの種類そのものを変える場合は、ページ種別を表す判定値の調整まで必要になる注意が書かれています。固定ページ内へ一覧を追加したいなら、Query Loop、get_posts()、WP_Queryから選びます。pre_get_postsとWP_Queryの使い分けでは、処理のタイミングも比べています。

同じ『最新3件』でも、置く場所で答えが変わる

よくある「最新3件」の要望を、置く場所まで含めて比べてみます。

「最新記事を3件表示したい」という要望だけでは方法を決められません。

たとえば、固定ページの本文に3件のカードを足したいのか、カテゴリー一覧そのものを1ページ3件にしたいのかで、変える場所が違います。「どのページの、どこに表示するか」「今ある一覧を変えるのか、新しい枠を足すのか」まで書いてみると、使う方法を選びやすくなります。

要件を最後まで書いた例選択理由
固定ページの本文へ最新3件を、編集者が見た目を調整できるカードで追加Query Loop取得とカードの見た目をエディターで管理できる
テンプレートから最新3件のIDを受け取り、ほかの処理へ渡すget_posts()+fields=ids表示ループやページ情報が不要で、配列を直接使える
記事の下へ最新3件を追加し、テンプレートタグで表示WP_Query専用のループを持ち、the_post()でテンプレートタグを使える
投稿一覧ページそのものをPHPで1ページ3件へ変更pre_get_postsメインクエリのposts_per_pageを変える処理だから

検索する時も「WordPress 最新記事 3件」だけでなく、「固定ページに追加」「カテゴリー一覧を変更」「ページネーションあり」「IDだけ取得」のように目的を足すと、合う方法を見つけやすくなります。

WP_Queryの取得条件をWP Query Builderで組み立てる

WP_Queryを使う方法に決めたら、投稿タイプ、絞り込み、並び順、表示件数をWP Query Builderで整理できます。今回のように通常投稿・3件・カテゴリーID 2・日付の新しい順を選び、生成した$argsを表示ループと合わせて使ってみましょう。

生成コードにはキャッシュや総件数の設定も含まれるため、本文の手書きコードとは値が異なることがあります。総ページ数も使うならno_found_rows=falseを確認します。Query Loopのブロック配置やpre_get_postsの対象判定は別に実装する部分です。

操作手順はWP Query Builderの使い方で説明しています。生成後は、置くテンプレート、表示HTML、エスケープ、リセットをこの記事の例と合わせて確認すると、取得から表示までつなげられます。

同じ投稿を4つの方法で扱って違いを確かめる

同じ「お知らせ」一覧を使い、3件を追加する場合と、今ある一覧を6件へ増やす場合を見比べてみましょう。WordPress 7.1/PHP 8.4.20のローカル環境で、カテゴリー「お知らせ」(ID 2)の公開投稿15件を対象にしています。新しい順の先頭3件は「メンテナンスのお知らせ」「春の更新情報」「確認用記事C」です。

get_postsとWP_Queryは、本文と同じ3件の条件です。pre_get_postsはカテゴリーのメインクエリ相当を作り、本文のフックで3件から6件へ変更します。Query Loopは投稿タイプpost・3件・日付降順・カテゴリーID 2・元のクエリを引き継がない設定で、WordPress標準のブロックを実際に描画します。先頭固定の優先は、追加する一覧の比較ではどれも無効にします。

確認項目結果
get_posts()で3件取得ID 13・10・63のWP_Post配列
同じ条件をWP_Queryで取得同じ3件、総件数15、総ページ数5
pre_get_postsでメインクエリを変更3件から6件へ。別の追加クエリは3件のまま
Query Loopを実際に描画ID 13・10・63のタイトルをリンク付きで表示

まずはget_posts()の結果です。取得した配列から、3件のタイトルと内容を一覧へ表示しています。

共通サンプルサイトのお知らせ一覧にget_postsで取得した3投稿を表示
get_posts配列から3件のお知らせを表示する

取得したIDは13・10・63。配列から取り出した投稿を、サンプルサイトの一覧部品で表示しています。

WP_Queryでも、同じ条件なら見た目の3件は同じです。違うのは、総件数15・全5ページという情報も使える点です。

同じサンプルサイトでWP_Queryが同じ3投稿を表示し、総件数15と全5ページを確認
WP_Query見た目は同じでも、ページ情報も受け取れる

ID 13・10・63の3件は同じです。WP_Queryには総件数15・全5ページの情報もあります。ページ送り自体はこの画面には実装していません。

次はpre_get_postsで、もともとの一覧を6件へ増やした例です。先頭3件に「確認用記事B」「確認用記事A」「関連記事:画像を軽くする方法」が続きます。

共通サンプルサイトのメイン一覧をpre_get_postsで3件から6件へ増やした結果
pre_get_posts今ある一覧を6件へ増やす

ID 13・10・63に62・61・27が加わりました。変更したのはメイン一覧だけで、別に実行した追加クエリは3件のままです。

最後はQuery Loopです。PHPで表示用の一覧を書かず、投稿タイトルのブロックを繰り返して3件を表示しています。

共通サンプルサイトにQuery Loopが実際に出力した3件のリンク付きタイトル
Query Loopブロック自身が一覧を描画する

ID 13・10・63のタイトルはWordPress標準ブロックの実出力です。共通のヘッダーとフッター内に配置しています。管理画面や本番環境の画面ではありません。

この結果は各方法の優劣ではなく、受け取れる情報と変更対象が異なることの確認です。実サイトでは投稿タイプ、公開状態、ユーザー権限、ページ送り、使用テーマを要件に合わせて再確認してください。

投稿一覧の方法を選ぶときによくある間違い

実装や公開へ進む前に、見落としやすい項目をまとめて確認します。

先に見直したい6項目

  • Query Loopで足りる一覧でも、先にPHPファイルを編集する
  • get_posts()から総ページ数を得ようとして、別の全件取得を追加する
  • 既存アーカイブを変えたいのに、テンプレート内で同じ条件のnew WP_Query()を実行する
  • pre_get_postsでメインクエリや画面を限定せず、管理画面や追加クエリまで変える
  • WP_Queryの独自ループ後にwp_reset_postdata()を書かない
  • 古いquery_posts()を見つけ、元の目的を確認せず別の方法へ置き換える

方法を変更する時は、取得条件まで同時に変えないでください。同じ投稿タイプ・件数・並び順で返り値と画面を比較し、置き換え後に条件を1つずつ足します。

WP_Query・get_posts()・pre_get_postsの公式資料

WP_Query、get_posts()、pre_get_posts、Query Loopで扱える範囲と、ページ数や既定値の違いは、次の公式資料で確認できます。

WordPress公式

確認に使った公式ドキュメント

変更対象と必要な情報から1つを選ぶ

方法が決まったら、少ない条件で同じ投稿が出ることから確かめます。0件・1件・複数件の表示、変更しない一覧への影響まで確認してから、本番へ反映してください。

本番へ反映する前の確認

  • 必要な投稿・表示項目・ページ情報が揃っている
  • 0件・1件・複数件で表示を確認した
  • 管理画面や変更しない一覧に影響していない
  • 追加ループ後の投稿データと、ページ送りを使う場合の2ページ目も正しい
  • 比較用コードを残さず、問題時に変更を戻せる
WP Query BuilderBuilderで条件を組み直す条件を選び、WP_Queryのコードを画面で作れます。Builderでクエリを作る

この記事を書いた人

Huddly

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

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

この記事の検証情報

検証環境

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

更新履歴

  • 2026年10月27日 初回公開

この記事を活用する

あとで見返す・共有する

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

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