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_postsis_admin() || !is_main_query() の確認後、$query->set('posts_per_page', N) などで値を変更します。category__not_inmeta_keyorderby など WP_Query のパラメータをすべて使用できます。WP_Query を新規作成するより軽量です。

お気軽にご相談ください

お見積りへ お問い合わせへ