こんにちは!WordPressの裏側の仕組みや、もっとスマートなコードの書き方に興味を持ってこのページを開いてくれたんですね。素晴らしい探究心です!
他のプログラミング言語やフレームワークを少し知っている方なら、「あれ? WordPressって、画面を表示するだけでなんでこんなに裏でたくさんデータベースに問い合わせ(クエリ)をしているんだろう?」と疑問に思ったことがあるかもしれません。
今回は、実務の現場で必ず直面する「WP_Queryの実行回数を減らすための、プライマリクエリとセカンダリクエリの分離」という極意について、基礎から本質まで優しく、そして深く解説していきますね。
ここをクリアすれば、あなたの書くWordPressコードは見違えるほど洗練され、サイトの表示速度も劇的に速くなりますよ。一緒にバッチリマスターしていきましょう!
—
1. なぜWordPressは「クエリの嵐」になりやすいのか?
まず、WordPressの基本的な仕組みをおさらいしておきましょう。
ブラウザからアクセスがあったとき、WordPressは「今、ユーザーは何のページを見ようとしているのか?」を判断し、メインとなるデータをデータベースから取得します。これが「プライマリクエリ(メインループ)」です。
イメージとしては、こんな感じです。
[ ブラウザからのリクエスト ]
↓
【プライマリクエリ】(WordPressが勝手に実行するメインの取得)
- 例:「カテゴリID: 5の記事一覧を10件取ってきて!」
↓
画面を表示!
これ自体はごく自然な動きなのですが、実務ではここに「サイドバーの最近の投稿」「フッターの人気記事」「おすすめカテゴリーのリスト」といった、メインとは関係ない別のデータを画面のあちこちで表示したくなりますよね。
ここで、よくある「やってはいけない実装」をしてしまうと大変なことになります。
陥りがちなアンチパターン:テンプレートファイルでの場当たり的なクエリ発行
例えば、`sidebar.php` の中で、何も考えずに新しい `WP_Query` を生で書いてしまうケースです。
5,
‘orderby’ => ‘comment_count’,
) );
if ( $sidebar_query->have_posts() ) :
while ( $sidebar_query->have_posts() ) : $sidebar_query->the_post();
// 記事の表示処理
endwhile;
wp_reset_postdata(); // リセット忘れに注意!
endif;
?>
これの何が問題か分かりますか?
WordPressのテンプレート構造(Header → Main Content → Sidebar → Footer)の中でこれをやると、データベースに対して重たいSQLクエリが何度もバラバラに発行されることになります。
ページの表示スピードが低下するだけでなく、MySQLサーバーのCPU負荷が跳ね上がる原因になるんです。これを私たちは「N+1問題の親戚」のようなものとして、極力避けなければなりません。
—
2. 解決策:「プライマリクエリ」と「セカンダリクエリ」の完全分離
この問題を鮮やかに解決するのが、「プライマリクエリとセカンダリクエリの役割をきっちり分ける」という設計思想です。
- プライマリクエリ(主役):
URLの解釈に基づいて、WordPressコアが自動的に実行するメインのクエリ。基本的にはこれに手を加えすぎず、そのページが本来必要とするデータだけを純粋に取得させます。
- セカンダリクエリ(脇役):
サイドバーやウィジェット、特殊なブロックなどで必要なデータを、メインとは独立して、かつ効率的に取得するクエリ。
そしてプロの現場では、このセカンダリクエリをあちこちに散らばらせるのではなく、「表示処理が始まる前(コントローラー層や `functions.php`、あるいは専用のテンプレートパーツが読み込まれる前)」にまとめて準備するというアプローチを取ります。
—
3. 実践!スマートなデータ分離とキャッシュ戦略のコード
それでは、実際にどのようなコードを書けばいいのか、具体的な実装例を見ていきましょう。
今回は、「メインの投稿一覧」を表示しつつ、「サイドバー用にコメント数が多い人気記事5件」を効率よく取得する構成を考えてみます。
ステップ1:プレフック(pre_get_postsなど)でメインを整え、データは変数に持たせる
まずは、あちこちのファイルで `new WP_Query` を乱立させるのをやめ、データをスマートに管理するイメージです。
/
function my_get_sidebar_popular_posts() {
// セカンダリクエリを発行
$args = array(
‘posts_per_page’ => 5,
‘orderby’ => ‘comment_count’,
‘no_found_rows’ => true, // ★超重要:ページャーを使わないなら、全件カウントSQLを省いて爆速化!
‘ignore_sticky_posts’ => 1, // 先頭固定記事の特殊処理をスキップして軽量化
);
$popular_query = new WP_Query( $args );
// 投稿オブジェクトの配列だけを抜き出しておく
return $popular_query->posts;
}
ここで登場した `no_found_rows => true` と `ignore_sticky_posts => 1` は、インデックスチューニングや不要なSQL発行を防ぐための、プロ必須のテクニックです。
ページネーション(「次のページへ」など)が不要なセカンダリクエリには、必ず `no_found_rows => true` を入れる癖をつけましょう。これだけで、MySQLが裏で行う余計な `SQL_CALC_FOUND_ROWS` の計算が走りなくなり、クエリが高速化します。
ステップ2:テンプレート側では綺麗にデータを流し込むだけ
先ほど用意した関数を、サイドバーのテンプレート(`sidebar.php`)で呼び出してみます。ここではもう重たい `new WP_Query` も、複雑なリセット処理も必要ありません。ただ渡されたデータをループさせるだけです。