【入門編】初心者向け:get_postsとWP_Query、どちらを使うべき?クエリ発行の観点から比較 – WordPress 内部コア・データベース構造とパフォーマンス最適化解析バイブル

こんにちは!WordPressの裏側の仕組みを紐解いていくと、開発が何倍も楽しく、そして強固なものになりますよね。

他のプログラミング言語やフレームワークを少し知っている方なら、「データを取得する関数がいくつもあるけど、結局どれを使えばいいの?」と疑問に思ったことがあるはずです。WordPressの代表的なデータ取得手段である `WP_Query` と `get_posts()` も、まさにその代表格ですね。

「初心者向けに優しく、でも本質は妥協せず」に、データベース負荷の観点からこの2つの違いをマスターしていきましょう。ここをクリアすれば、あなたのWordPress開発スキルは一段と洗練されますよ!

—

1. そもそも、この2つの「裏側」はどうなっているの?

まず大前提として知っておいてほしいことがあります。
それは、「`get_posts()` の中身は、実は `WP_Query` そのものである」 という事実です。

[ あなたの書いたコード ]
│
├─► WP_Query クラスを直接召喚する ──► 最も生々しいクエリの制御が可能
│
└─► get_posts() 関数を使う ─────► 中身で WP_Query をこっそり呼び出している(ラッパー関数)

「あれ、じゃあ同じなの?」と思いますよね。
実は、「料理人(`WP_Query`)が自分でフルコースを作るのか、それともデリバリー(`get_posts()`)で手軽に定食を受け取るのか」 という決定的な違いがあります。

この違いが、データベース(MySQL)への負荷や、コードの書きやすさに大きく影響してくるんです。

—

2. それぞれの基本的な使い方とコードの読み方

まずは、それぞれの書き方を見てみましょう。他の言語から来た方にも馴染みやすいように、具体的なコードとコメントを用意しました。

パターンA:`WP_Query`(本格派シェフのフルコース)

自分でクラスをインスタンス化し、取得したデータのループ処理だけでなく、グローバルな投稿データ( `$post` )の巻き戻し(後述します)まで自分で責任を持つスタイルです。

‘post’,
‘posts_per_page’ => 5,
‘category_name’ => ‘news’,
);

$my_query = new WP_Query( $args );

// 2. データベースから持ってきたデータがあるかチェックしてループ開始
if ( $my_query->have_posts() ) :
while ( $my_query->have_posts() ) : $my_query->have_posts(); // ※正しくは $my_query->the_post() ですね!うっかりミスに注意!
// 正しいループの書き方:
// $my_query->the_post();
?>

パターンB:`get_posts()`(手軽なデリバリー定食)

こちらは配列を返すだけのシンプルな関数です。オブジェクト指向の面倒な作法を意識せず、サクッと配列データを取得したいときに使われます。

‘post’,
‘posts_per_page’ => 5,
‘category_name’ => ‘news’,
);

$recent_posts = get_posts( $args );

// 2. 返ってきたのは普通の配列なので、foreachで回すだけ!
if ( ! empty( $recent_posts ) ) {
echo ‘

    ‘;
    foreach ( $recent_posts as $post ) {
    // 注意:setup_postdata() をしないとテンプレートタグ(the_title()など)が使えない場合があります
    setup_postdata( $post );
    echo ‘

  • ‘ . get_the_title( $post->ID ) . ‘
  • ‘;
    }
    echo ‘

‘;

// 3. こちらも必ずリセットが必要
wp_reset_postdata();
}

—

3. データベース負荷とパフォーマンスの観点からの比較

さて、ここからがエンジニアとしての腕の見せ所です。
「どちらを使っても同じ記事が取れるなら、短いコードのほうがいいや」と思っていませんか?

実は、データベース(MySQL)やメモリ効率の観点から見ると、それぞれに適材適所の使い分けが存在します。

① 発行されるSQLクエリの差はある?

結論から言うと、指定する引数(`$args`)が同じであれば、生成されるSQL文自体は基本的に同じです。どちらも内部で `WP_Query` が動いているため、`SELECT FROM wp_posts …` のような重いクエリが発行されます。

では、何が違うのでしょうか?

② メモリ消費と「余計な機能」の有無

  • `WP_Query`(特にページネーションを使う場合)
  • `’no_found_rows’ => false` (デフォルト)の場合、WordPressは「この条件に一致する全データの総数(MAX件数)」を計算するために、`SQL_CALC_FOUND_ROWS` という重い処理をSQLに含めます。これにより、データベースサーバーへの負荷が跳ね上がることがあります。
  • `get_posts()`
  • デフォルトで `’suppress_filters’ => true` や `’no_found_rows’ => true` が内部的に考慮されているケースが多く、「総件数(ページネーション用の全体数)を計算しない」軽量な設定で動きやすいという特徴があります。ページネーションを必要としない「新着情報リスト」などを表示する場合、データベースへの無駄な負荷を抑えられます。

—

4. 陥りがちな文法エラーとトラップ

初学者が必ずと言っていいほどハマるポイントが2つあります。ここを知っておくだけで、現場でのデバッグ時間が何時間も削減されますよ。

トラップ1:`the_post()` と `setup_postdata()` の違いによるバグ

WordPressの便利なタグ(`the_title()` や `the_content()` など)は、裏側で「グローバル変数 `$post`」を頼りに動いています。

  • `WP_Query` のループ内では、`$my_query->the_post()` を使えば自動でこれが設定されます。
  • 一方、`get_posts()` は単なる配列を返すだけなので、ループ内で明示的に `setup_postdata( $post );` を呼ばないと、タイトルのリンクがおかしくなったり、同じ記事のタイトルがループし続けたりする怪奇現象が起きます。

トラップ2:メインクエリの汚染と `wp_reset_postdata()` の忘れ

カスタムクエリを書いた後、`wp_reset_postdata()` を書き忘れるとどうなるでしょう?
ページ本来のメインクエリ(そのページが本来持っている記事情報)が、あなたの書いたカスタムクエリのデータに書き換わったままになってしまいます。その結果、サイドバーのウィジェットがおかしくなったり、コメント欄が消えたりという不可解なバグを生む原因になります。「クエリを書いたら、必ずリセットする」 はエンジニアの絶対のルールです。

—

5. 結局、どちらを使うべきなのか?(選択の基準)

ここまでの知見をまとめると、シンプルに次のように使い分けるのがベストプラクティスです。

| 状況・目的 | 推奨する関数 | 理由 |
| :— | :— | :— |
| アーカイブページやメインのブログ一覧
(ページネーション(1, 2, 3…)が必要) | `WP_Query`
(またはメインクエリをそのまま利用) | ページネーションに必要な全件数を正確に算出するため。 |
| トップページの「新着5件」やサイドバーの「おすすめ記事」
(ページネーション不要) | `get_posts()`
(または `WP_Query` で `no_found_rows => true` 指定) | ページネーション用の重いカウント処理を省き、データベースの負荷を最小限に抑えるため。 |

—

まとめ

いかがでしたか? `get_posts` と `WP_Query` は、単なる「書き方の好み」ではなく、データベースの裏側の挙動やパフォーマンスに直結する重要な選択です。

「とりあえず動くからいいや」ではなく、「なぜこの関数を選ぶのか」を意識できるようになると、WordPressはただのブログツールではなく、強力でスケーラブルなWebアプリケーション基盤へと姿を変えます。

ここをクリアしたあなたなら、どんな複雑な要件の案件が来ても怖くありませんよ。自信を持って次のステップへ進んでいきましょう!

タイトルとURLをコピーしました