【WordPressテーマの作り方 第11回】get_postsとWP_Queryの違いをマスターしよう(投稿の取得)

WordPressで投稿を取得する方法といえば、get_posts()WP_Query
この記事では「どちらを使えばいいのか」「失敗しない使い分け方」を初心者にもわかりやすく解説します。

get_posts()とWP_Query、どちらが正解なのか? 実は、それぞれ役割がまったく違うんです。

目次

✅ 今回のゴール

よくある失敗や注意点まで学び、実案件に活かせる力をつける

get_posts()WP_Query の違いを理解する

シンプルな一覧取得/複雑な条件分岐の使い分けができるようになる

「投稿を一覧で表示したい」その時、どっちを使う?

WordPressでよくあるお悩み:

  • 「最新記事をサイドバーに出したい…」
  • 「カテゴリで絞り込んだ一覧を作りたい…」
  • 「カスタム投稿を条件付きでループしたい…」

そんなときに使えるのが、
get_posts()WP_Query の2つの投稿取得手段です。

ただしこの2つ、向き不向きがハッキリしてるのが要注意!

今回は、WordPressで「投稿一覧を出したい」ときによく使う get_posts()WP_Query の違いを整理し、それぞれの使いどころをわかりやすく紹介していきます!
WordPress 投稿取得の基本をおさえたい」という方にピッタリの内容です。

1. get_posts() の特徴

🧩 シンプルな投稿取得

WordPressで最も手軽に投稿を取得できるのが get_posts()サッと投稿を数件だけ取りたい時にピッタリです。
取得結果は「投稿オブジェクトの配列」で返ってきます。

<?php
// 最新の通常投稿(post)を5件、日付の新しい順で取得
$latest_posts = get_posts([
  'posts_per_page' => 5,
  'post_type' => 'post',
  'orderby' => 'date',
  'order' => 'DESC',
]);

// 各投稿に対してループ処理を行う
foreach ($latest_posts as $post) :
  // 投稿データを WordPress のグローバル変数に設定(テンプレートタグが使えるように)
  setup_postdata($post);
?>
  <li><a href="<?php the_permalink(); ?>"><?php the_title(); ?></a></li>
<?php
endforeach;
// 投稿データの状態を元に戻す(ループ後は毎回必要)
wp_reset_postdata();
?>

💡 注意点

  • query_posts() と違ってメインループを壊さない
  • ページネーションには対応していない
  • ループ状態を操作するには setup_postdata()wp_reset_postdata() が必要

👉 軽量・高速だが、機能はシンプル。
一覧ページよりも サイドバーやフッター向け

📌 ページネーションや複雑な条件での絞り込みが必要な場合は WP_Query に切り替えましょう。

※補足:実は get_posts() は内部的に WP_Query を呼び出しています。つまり「簡易版WP_Query」とも言えますが、機能が制限されているぶん、軽量で高速です。

2. WP_Query の特徴

🔍 柔軟で多機能、なんでも対応

WordPressで複雑な条件で投稿を取得したいなら、やはり WP_Query の出番。投稿タイプやカスタムフィールドを組み合わせた絞り込みも得意です。
カスタム投稿、タクソノミー、メタ情報など複雑な条件でも対応可能です。

<?php
// 投稿タイプ「news」から、カスタムフィールド「important」が「1」の投稿を10件取得
$args = [
  'post_type' => 'news',
  'posts_per_page' => 10,
  'meta_key' => 'important', // 絞り込み対象のカスタムフィールド
  'meta_value' => '1'        // 「1」の投稿のみ対象
];

// WP_Query のインスタンスを作成
$news_query = new WP_Query($args);

// 投稿が存在する場合にループ処理を開始
if ($news_query->have_posts()) :
  while ($news_query->have_posts()) :
    $news_query->the_post(); // 投稿データを1件分取得
?>
  <article><h2><?php the_title(); ?></h2></article>
<?php
  endwhile;
  // 投稿データの状態をリセット(メインクエリに戻す)
  wp_reset_postdata();
endif;
?>

💡 注意点

  • 書き方がやや長め
  • 複雑な条件ではデータベース負荷が増える
  • ページネーションも制御できる(max_num_pages など)

👉 強力だが、慎重に使う必要あり。

3. 使い分けの目安

使用ケース推奨
サイドバーで「最新投稿」を数件表示したいget_posts()
ページ送り付きの一覧ページを作りたいWP_Query
カスタム投稿・カスタムフィールドを使うWP_Query
数件だけ取得して処理したい(軽量)get_posts()

💡get_posts() と WP_Query の使い分けに迷ったら、このルールを思い出しましょう:

  • 「軽い・少ない → get_posts()」
  • 「複雑・多い → WP_Query」

🪄 あえてさらに深掘るなら…

🔸 pre_get_posts フィルターで全体を制御

たとえば、トップページで特定カテゴリを除外したい場合:

// トップページの投稿一覧から、カテゴリID「5」の記事を除外
function modify_home_query($query) {
  // 管理画面 or メインクエリ以外は処理しない
  if (is_admin() || !$query->is_main_query()) return;

  // フロント側トップページに対してのみ適用
  if ($query->is_home()) {
    $query->set('cat', '-5'); // マイナス値でカテゴリ除外
  }
}
add_action('pre_get_posts', 'modify_home_query');

⚠️ よくある失敗

  • is_main_query() を忘れると管理画面や他のクエリに影響して大事故に
  • 管理画面だけ除外したいときは is_admin() を必ず併用
// 「event」投稿タイプのアーカイブページを「event_date」フィールドの昇順で並び替え
function modify_event_archive($query) {
  if (!is_admin() && $query->is_post_type_archive('event') && $query->is_main_query()) {
    $query->set('orderby', 'meta_value');  // カスタムフィールドの値でソート
    $query->set('meta_key', 'event_date'); // 対象となる日付フィールド
    $query->set('order', 'ASC');           // 昇順(古い順)
  }
}
add_action('pre_get_posts', 'modify_event_archive');

💡 さらに応用すれば、カスタム投稿のアーカイブ表示も自由自在に制御できます:

🔸 WP_Query を JSON形式で返す応用例

▼ 例:独自 REST API エンドポイントで WP_Query を返す

// 独自REST APIエンドポイント(/wp-json/custom/v1/events/)を登録
add_action('rest_api_init', function() {
  register_rest_route('custom/v1', '/events/', [
    'methods'  => 'GET',
    'callback' => 'get_custom_events',
  ]);
});

function get_custom_events() {
  // 投稿タイプ「event」から5件取得
  $query = new WP_Query([
    'post_type' => 'event',
    'posts_per_page' => 5,
  ]);

  $results = [];
  while ($query->have_posts()) {
    $query->the_post();
    // タイトルとリンクを整形して配列に追加
    $results[] = [
      'title' => get_the_title(),
      'link'  => get_permalink(),
    ];
  }

  wp_reset_postdata();

  // 結果をJSON形式で返す
  return rest_ensure_response($results);
}

このコードを入れると、/wp-json/custom/v1/events/ にアクセスしたときに「イベント投稿5件」がJSONで返るようになります。
これを JavaScript の fetch() などで取得して、表示に使うことも可能です。

💡 応答に日付やカスタムフィールドを含めたい場合は、get_the_date()get_field() を追加するだけでOKです。

💬 よくある質問(Q&A)

Q. get_posts() でページ送りできますか?
→ できません。ページネーション対応は WP_Query 一択です。

Q. WP_Query は重いの?
→ 条件が多くなるとクエリも重くなります。
 fields => 'ids' でIDだけ取得する軽量化テクも有効です。

Q. query_posts() はもう使わないの?
→ 原則非推奨。メインクエリを壊してしまうため、今後は避けるべきです。

Q. 複数ループでうまく動かない…?
the_post() の連続呼び出しや wp_reset_postdata() の入れ忘れが原因かも。
 ループの切り替え後は必ず状態を戻しましょう。

📝 まとめ

  • 🔹 WordPressで投稿を取得するなら、get_posts() は「軽量」「すばやく数件だけ取得」に最適
    一方で、柔軟に条件を加えたい場合は WP_Query の出番です
  • 🔹 WP_Query は「複雑な絞り込み」「ページネーション」「カスタム投稿」に対応
  • 🔹 pre_get_posts を使えば グローバルな制御 も可能
  • 🔹 is_main_query() の有無や wp_reset_postdata() の使い方に注意!

📝 次回予告:「固定ページと投稿ページの違い・テンプレート階層を深掘り!」

次回は、page.phpsingle.php の違い、テンプレート階層のルール、条件分岐の仕組みなど、WordPressの裏側ロジックを紐解いていきます!

「テンプレート階層って何?」「page.php と single.php の違いが曖昧…」そんなモヤモヤを一気にクリアにします!

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

Web制作会社勤務、業界歴10年以上。現場を走り回ってきた制作者。
これからWeb制作を学ぶ人に寄り添いながら、実務で役立つ知識をわかりやすくシェアします。
「ゼロぐらいから学べる!」をモットーに、あなたの“がんばろ”を応援します!

目次