WordPressで投稿一覧を出すコードを調べると、 「query_posts()」「WP_Query()」「get_posts()」 の3種類があります。
どれも「投稿を取得する関数」ですが、実はそれぞれの動作の仕組みや影響範囲がまったく異なります。
- ページネーションが動かなくなる
- 「先頭に固定表示」が効かない
- メインクエリが壊れて他のパーツに影響する
といったトラブルを引き起こすこともあります。
本記事では、この3つの関数の違い・使い分け・おすすめの実装方法をわかりやすく解説します。
コードを書くたびに「どれを使えばいいんだっけ?」と悩む方は、この記事でスッキリ整理できます。
3つの関数の役割と基本的な違い
WordPressで投稿を取得する関数は複数ありますが、実はそれぞれ「どのクエリを扱うか」が大きな違いです。
| 関数名 | 役割 | メインクエリへの影響 | ページネーション | 固定表示(Sticky)対応 | 主な用途 |
|---|---|---|---|---|---|
| query_posts() | すでに存在するメインクエリを書き換える | あり(上書きする) | 壊れることが多い | 効かないことがある | 簡易的な調整(非推奨) |
| WP_Query() | 新しいクエリを独立して作る | なし | 正常に使える | デフォルトでは無効(設定で可) | サブループ・独自一覧の出力 |
| get_posts() | 投稿を配列で取得する(軽量) | なし | 使えない(全件固定) | 無効 | スライダーやサイドバーなど軽い用途 |
- query_posts() … 「今あるメインクエリを書き換える」ので壊れやすい。基本は使わない。
- WP_Query() … 最も汎用的で、独自ループを作るならこれ。
- get_posts() … テンプレート内で軽くデータだけ取りたいとき用。
3つとも「投稿を取得する」ことはできますが、WordPress内部で扱う仕組み(メインクエリ・サブループ・配列処理)が異なるため、使い分けが重要です。
query_posts() の特徴と注意点(非推奨の理由)
query_posts() は、WordPress が最初に作成した メインクエリ($wp_query)を上書き する関数です。
一見シンプルに投稿の取得条件を変更できるように見えますが、実際には多くの不具合を引き起こす原因になります。
メインクエリを上書きしてしまう
通常、WordPress ではページごとに「どんな投稿を表示するか」が決まっており、
これをメインクエリ($wp_query)が管理しています。
query_posts() を使うとこのメインクエリを再実行して上書きしてしまうため、
ページネーションが効かなくなる、条件付きタグ(is_home, is_category など)が壊れる といった問題が発生します。
「先頭に固定表示」やプラグインの挙動に影響する
さらに、query_posts() は内部的に WP_Query を再生成する形をとるため、固定表示(sticky posts)やプラグインによるクエリフックが正しく動作しないことがあります。
対処法:pre_get_posts か WP_Query() に書き換える
もしメインクエリの条件を変更したいだけなら、テンプレート階層でのメインクエリを書き換える pre_get_posts フック を使うのが安全です。
//例:1ページに表示する最大投稿数を6件に変更
function custom_modify_main_query($query) {
if ( is_home() && $query->is_main_query() ) {
$query->set('posts_per_page', 6);
}
}
add_action('pre_get_posts', 'custom_modify_main_query');
また、メインクエリに影響を与えず独自に投稿を取得したい場合は、次に紹介する WP_Query() を使うのがベストです。
WP_Query() の特徴と使い方
WP_Query は WordPress の投稿を取得するためのクラス(仕組み)です。
「新しいクエリを自分で作って、好きな条件で投稿を表示したい」ときに使います。
主な特徴まとめ
| 特徴 | 内容 |
|---|---|
| 🔸 新しいクエリを作れる | メインループとは別に、任意の条件で投稿を取得できる。 |
| 🔸 柔軟な条件指定が可能 | 投稿タイプ・カテゴリー・タグ・並び順・メタ情報など、細かく設定可能。 |
| 🔸 ループ制御が必要 | 取得結果を while ループで回して出力する必要がある。 |
| 🔸 メインクエリを壊さない | query_posts() と違い、WordPressの標準動作に影響を与えない。 |
つまり、安全にサブクエリを扱える柔軟な方法が WP_Query() です。
基本構文
$args = array(
'post_type' => 'post', // 投稿タイプ(投稿、固定ページ、カスタム投稿など)
'posts_per_page' => 3, // 表示件数
'orderby' => 'date', // 並び替え基準
'order' => 'DESC', // 昇順 or 降順
'category_name' => 'news', // 特定のカテゴリを指定
);
$the_query = new WP_Query($args); // クエリを作成
if ( $the_query->have_posts() ) : // 投稿があるかチェック
while ( $the_query->have_posts() ) : $the_query->the_post();
the_title('<h2>', '</h2>');
the_excerpt();
endwhile;
wp_reset_postdata(); // グローバル変数を元に戻す(重要)
endif;
各部分の説明
| 部分 | 役割 |
|---|---|
$args | 取得条件を配列で指定。カテゴリーや件数などを細かく設定できる。 |
new WP_Query($args) | 条件に合う投稿を取得するオブジェクトを生成。 |
have_posts() / the_post() | ループ処理を行うためのメソッド。 |
wp_reset_postdata() | メインクエリに戻すための関数。これを忘れると次のループで不具合が起きる。 |
よくある使用シーン
| シーン | コード例 |
|---|---|
| 最新の投稿3件を表示 | 'posts_per_page' => 3 |
| 「お知らせ」カテゴリのみ取得 | 'category_name' => 'news' |
| カスタム投稿タイプ「works」から表示 | 'post_type' => 'works' |
| タグ「design」を含む投稿 | 'tag' => 'design' |
メリット・デメリット
| 項目 | メリット | デメリット |
|---|---|---|
| 柔軟性 | 取得条件を細かく設定できる | ループ処理がやや長くなる |
| 安全性 | メインクエリを壊さない | コード量が増える場合あり |
| 拡張性 | カスタム投稿やメタ情報も簡単に指定可 | PHP初心者には少し複雑に感じる |
ワンポイント
WP_Query() は、「メインループ(投稿一覧)」とは別に投稿を表示したいときに使うのが基本です。
- トップページの下部に「最新のお知らせ」だけを出したい
- サイドバーに「人気記事」一覧を表示したい
- カスタム投稿タイプ(例:制作実績)を表示したい
といったケースでは、WP_Query() が最も使われます。
get_posts()の特徴と注意点
get_posts() は、WP_Query を簡易的にラップした関数で、軽量に投稿リストを取得したいときに使われます。
たとえば「最新3件だけをサイドバーに出す」など、単純な一覧表示に最適な関数です。
WP_Query よりも機能が省略されているので、設定や挙動を正しく理解しておかないと意図しない結果になることもあります。
ここでは、よくある失敗を踏まえて解説します。
デフォルトで ignore_sticky_posts = true
get_posts() は内部的に WP_Query を使っていますが、デフォルトで ignore_sticky_posts が true(= 固定表示を無視)に設定されています。
そのため、トップページなどで「先頭に固定表示」にした投稿を取得したい場合、get_posts() を使うと除外されてしまうことがあります。
📌 対処法として、以下のように明示的に ignore_sticky_posts => false を指定します。
$args = array(
'posts_per_page' => 5,
'ignore_sticky_posts' => false, // 固定表示も含める
);
$posts = get_posts($args);
この1行を入れるだけで、sticky 設定された投稿も取得対象になります。
シンプルだが柔軟性に欠ける
get_posts() の特徴は「軽くて速い」こと。
ただしその分、取得条件や制御が制限される点には注意が必要です。
| 項目 | WP_Query | get_posts |
|---|---|---|
| 柔軟な条件指定 | ◎ 可能(複雑な条件もOK) | △ 一部のみ対応 |
| ページング(ページ送り) | ◎ 対応 | × 対応していない |
| 投稿数制御 | ◎ posts_per_pageで指定 | ○ posts_per_pageで指定可能 |
| 固定表示投稿 | デフォルトで反映 | デフォルトで無視(要設定) |
| メインクエリとの干渉 | なし | なし(安全) |
つまり、get_posts() は「一覧を軽く出したいとき専用」。
ページネーションや検索結果表示のような複雑なクエリには向きません。
ループ内で the_post() を使う場合の注意
get_posts() は投稿データの配列を返すため、WP_Query のように自動で $post グローバル変数を更新しません。
そのまま the_title() や the_content() を使うと、正しい投稿情報が出力されないことがあります。
📍正しい書き方は以下のようになります。
$posts = get_posts(array(
'posts_per_page' => 3
));
foreach ($posts as $post) :
setup_postdata($post); // グローバル変数にセット
?>
<h2><?php the_title(); ?></h2>
<p><?php the_excerpt(); ?></p>
<?php
endforeach;
wp_reset_postdata(); // 元に戻す
setup_postdata() を呼ぶことで、the_title() や the_permalink() などのテンプレートタグが正しく動作します。
get_posts()のまとめ:軽量な用途と制約
| 向いているケース | 向いていないケース |
|---|---|
| サイドバーの最新投稿リスト | ページネーションを伴う一覧 |
| 固定数の関連記事表示 | 検索結果・アーカイブページ |
| カスタム投稿を数件だけ取得 | 複雑な条件を組み合わせたいとき |
get_posts() は「軽くてシンプル」。
ただし、「固定表示投稿を含めたい」「ページ送りをしたい」場合には、WP_Query() を選ぶのが確実です。
3つの関数の使い分け早見表
WordPressで投稿を取得する主な関数は、「query_posts()」「WP_Query」「get_posts()」の3つです。
目的によって最適な使い分けがあるので、以下の表を参考に、状況に応じて正しい関数を選びましょう。
| 用途 | 最適な関数 | 補足 |
|---|---|---|
| メインクエリを条件変更したい | pre_get_posts | query_posts() は使わない |
| サブループで一覧を出したい | WP_Query | 投稿一覧・カスタム投稿などに最適 |
| 固定ページ内で特定記事だけ出したい | get_posts | 軽量処理に向く・ページング非対応 |
query_posts()はメインクエリを上書きしてしまうため、テーマやプラグインとの競合を起こすリスクがあります。- 一般的には、サブループを作る場合は
WP_Query、軽量に数件だけ取得したいときはget_posts、既存クエリを変更したい場合はpre_get_postsを使うのがベストです。
実践例|同じ条件で3つの方法を比較
では実際に、「最新の投稿を3件だけ表示する」という同じ条件を、3つの方法で書き比べてみましょう。
コードの見た目や動作の違いがわかりやすくなります。
1.query_posts() の場合(非推奨)
<?php
query_posts(array(
'posts_per_page' => 3,
));
if (have_posts()) :
while (have_posts()) : the_post();
the_title();
endwhile;
endif;
wp_reset_query();
?>
query_posts() はメインクエリを直接上書きします。
プラグインやページネーションとの競合が起きやすく、公式ドキュメントでも非推奨とされています。
2.WP_Query の場合(推奨)
<?php
$args = array(
'posts_per_page' => 3,
);
$query = new WP_Query($args);
if ($query->have_posts()) :
while ($query->have_posts()) : $query->the_post();
the_title();
endwhile;
endif;
wp_reset_postdata();
?>
- メインクエリを壊さず、サブループとして安全に使える
- カスタム投稿タイプや複雑な条件にも対応できる
- 実務でも最も一般的な方法です
3.get_posts() の場合(軽量)
<?php
$args = array(
'posts_per_page' => 3,
'ignore_sticky_posts' => false, // 固定表示を含めたい場合
);
$posts = get_posts($args);
foreach ($posts as $post) :
setup_postdata($post);
the_title();
endforeach;
wp_reset_postdata();
?>
- 軽量で、配列として投稿データを返す
- ページネーション非対応
- サイドバーやウィジェットなど、ちょっとした一覧出力に最適
まとめ|正しく使い分けてトラブルを防ごう
WordPressの投稿取得は、一見似たような関数でも挙動が大きく異なります。
間違った関数を使うと、意図しない表示や不具合の原因になることも。
以下を押さえておけば安心です👇
query_posts()は基本使わない(非推奨)WP_Query()は汎用的で安全(メインでもサブでもOK)get_posts()は軽量だが制約あり(簡易用途向け)pre_get_postsを使えばテーマ改修に強い(条件変更を安全に実装可能)
正しい関数を選べば、テーマの保守性やSEOにもプラスに働きます。
特に実務では、WP_Query+pre_get_posts の組み合わせが最も安心です。





コメント