2026年5月20日
2026年5月20日
WordPressのpre_get_posts()でメインクエリを変更する方法
はじめに
pre_get_posts フックはWordPressがデータベースにクエリを送る前にメインクエリを変更できます。WP_Query で別クエリを作るより軽量で、テンプレートのPHPを変更せずにアーカイブページの動作を変えられます。
症状・原因
- ブログ一覧の表示件数を変えたい
- 特定カテゴリをトップページから除外したい
- カスタム投稿タイプのアーカイブに表示件数を設定したい
- 管理画面には影響させずフロント側だけ変更したい
解決手順
ステップ1:基本構造と重要な条件分岐
// functions.php
add_action('pre_get_posts', function(WP_Query $query): void {
// 必須: 管理画面とサブクエリは除外
if (is_admin() || !$query->is_main_query()) {
return;
}
// ここにクエリ変更を記述
});
is_admin() と is_main_query() のチェックは必須です。これがないと管理画面の投稿一覧や、テンプレート内のサブクエリも影響を受けます。
ステップ2:表示件数を変更する
add_action('pre_get_posts', function(WP_Query $query): void {
if (is_admin() || !$query->is_main_query()) return;
// ブログ一覧を12件表示
if ($query->is_home()) {
$query->set('posts_per_page', 12);
}
// カテゴリアーカイブを20件表示
if ($query->is_category()) {
$query->set('posts_per_page', 20);
}
// 検索結果を10件表示
if ($query->is_search()) {
$query->set('posts_per_page', 10);
}
});
ステップ3:特定カテゴリを除外する
add_action('pre_get_posts', function(WP_Query $query): void {
if (is_admin() || !$query->is_main_query()) return;
// トップページと一般アーカイブから「お知らせ(ID:5)」を除外
if ($query->is_home() || $query->is_archive()) {
$query->set('category__not_in', [5]);
}
});
// スラッグで除外する場合
add_action('pre_get_posts', function(WP_Query $query): void {
if (is_admin() || !$query->is_main_query()) return;
if ($query->is_home()) {
$cat = get_category_by_slug('news');
if ($cat) {
$query->set('category__not_in', [$cat->term_id]);
}
}
});
ステップ4:カスタム投稿タイプのアーカイブを設定する
add_action('pre_get_posts', function(WP_Query $query): void {
if (is_admin() || !$query->is_main_query()) return;
// CPT「news」のアーカイブ
if ($query->is_post_type_archive('news')) {
$query->set('posts_per_page', 15);
$query->set('orderby', 'date');
$query->set('order', 'DESC');
}
// タクソノミー「news_category」のアーカイブ
if ($query->is_tax('news_category')) {
$query->set('posts_per_page', 15);
}
});
ステップ5:カスタムフィールドでソートする
add_action('pre_get_posts', function(WP_Query $query): void {
if (is_admin() || !$query->is_main_query()) return;
// アーカイブを「_event_date」カスタムフィールドでソート
if ($query->is_post_type_archive('event')) {
$query->set('meta_key', '_event_date');
$query->set('orderby', 'meta_value');
$query->set('order', 'ASC');
$query->set('meta_query', [
[
'key' => '_event_date',
'value' => date('Y-m-d'),
'compare' => '>=',
'type' => 'DATE',
]
]);
}
});
注意事項
pre_get_postsはメインクエリを直接変更するため、WP_Queryで別クエリを作るより効率的ですが、is_admin()とis_main_query()の確認を忘れると管理画面や他のクエリも影響を受けます$query->set('posts_per_page', -1)は全件取得になりパフォーマンスに悪影響です。必要最低限の件数を指定してください- フロントページが「最新の投稿」の場合は
$query->is_home()でチェックします。固定ページをトップページに設定している場合は$query->is_front_page()を使います
まとめ
pre_get_posts は is_admin() || !is_main_query() の確認後、$query->set('posts_per_page', N) などで値を変更します。category__not_in・meta_key・orderby など WP_Query のパラメータをすべて使用できます。WP_Query を新規作成するより軽量です。