2026年5月20日
2026年5月20日
WordPressのpre_get_postsでメインクエリを変更する方法|件数・除外・並び順
pre_get_posts は、WordPress が投稿を取得するクエリ(WP_Query)を、データベースに問い合わせる直前に書き換えられるアクションフックです。テンプレートを書き換えずに、ブログ一覧やアーカイブの表示件数・並び順・対象の投稿を変えられます。テンプレートの中で別の WP_Query を作る方法と違い、メインクエリそのものを変えるので、ページ送りの件数もずれません。
この記事の内容は、2026年10月時点の WordPress 開発者リファレンス(pre_get_posts と WP_Query)で確認しています。
基本の形
コードは、子テーマの functions.php か、コードスニペット用のプラグインに追加します。
<?php
add_action( 'pre_get_posts', function ( WP_Query $query ): void {
// 管理画面と、メイン以外のクエリは変えない
if ( is_admin() || ! $query->is_main_query() ) {
return;
}
// ここに変更を書く
} );
押さえておく点は次の3つです。
pre_get_postsは、メインクエリだけでなく、ウィジェットの最近の投稿、テンプレート内のWP_Query、get_posts()など、すべてのWP_Queryで実行されます。$query->is_main_query()で、ページの表示に使うメインクエリだけに絞ります。- 管理画面の投稿一覧もメインクエリです。
is_admin()で除かないと、管理画面の一覧の件数や並び順まで変わります。 - 条件分岐は、関数版(
is_home()など)ではなく、渡された$queryのメソッド($query->is_home()など)を使います。開発者リファレンスによると、この時点ではis_front_page()は正しく動かず、is_home()は動きます。
$query は参照で渡されるため、値を返す必要はありません。$query->set( 'キー', 値 ) で、WP_Query の引数を変えます。
表示件数を変える
ページの種類ごとに件数を変える例です。何も指定しないページは「設定」→「表示設定」の「1ページに表示する最大投稿数」のままです。
<?php
add_action( 'pre_get_posts', function ( WP_Query $query ): void {
if ( is_admin() || ! $query->is_main_query() ) {
return;
}
if ( $query->is_home() ) {
// 投稿一覧(ブログのトップ)
$query->set( 'posts_per_page', 12 );
} elseif ( $query->is_category() ) {
// カテゴリーアーカイブ
$query->set( 'posts_per_page', 20 );
} elseif ( $query->is_search() ) {
// 検索結果
$query->set( 'posts_per_page', 10 );
}
} );
$query->is_home() は、ブログの投稿一覧のページで真になります。「ホームページの表示」を「最新の投稿」にしている場合はトップページ、固定ページをホームページにしている場合は「投稿ページ」に指定した固定ページの URL が、これに当たります。
posts_per_page に -1 を指定すると全件を1ページに出します。投稿が多いサイトではページの表示が遅くなるため、上限のある数を指定してください。
特定のカテゴリーを一覧から除く
ブログのトップから「お知らせ」カテゴリー(スラッグ news)の投稿を除く例です。
<?php
add_action( 'pre_get_posts', function ( WP_Query $query ): void {
if ( is_admin() || ! $query->is_main_query() || ! $query->is_home() ) {
return;
}
$news = get_category_by_slug( 'news' );
if ( $news ) {
$query->set( 'category__not_in', array( $news->term_id ) );
}
} );
- ID が分かっている場合は
array( 5 )のように直接書けますが、スラッグから ID を取るほうが、別の環境に移したときに間違いが起きにくくなります。 - 条件に
$query->is_archive()を加えると、「お知らせ」カテゴリー自身のアーカイブまで空になります。除く範囲は、上のように対象のページに絞ってください。 category__not_inは、指定したカテゴリーの子カテゴリーの投稿は除きません。子カテゴリーも除く場合は、その ID も配列に加えます。
カスタム投稿タイプのアーカイブを設定する
カスタム投稿タイプ news のアーカイブと、カスタムタクソノミー news_category のアーカイブの件数と並び順を変える例です(投稿タイプは has_archive を有効にして登録されている前提です)。
<?php
add_action( 'pre_get_posts', function ( WP_Query $query ): void {
if ( is_admin() || ! $query->is_main_query() ) {
return;
}
if ( $query->is_post_type_archive( 'news' ) || $query->is_tax( 'news_category' ) ) {
$query->set( 'posts_per_page', 15 );
$query->set( 'orderby', 'date' );
$query->set( 'order', 'DESC' );
}
} );
カスタムフィールドで並べ替える
カスタム投稿タイプ event のアーカイブで、カスタムフィールド _event_date(2026-11-20 の形で保存)を使い、今日以降のイベントを日付の近い順に並べる例です。
<?php
add_action( 'pre_get_posts', function ( WP_Query $query ): void {
if ( is_admin() || ! $query->is_main_query() || ! $query->is_post_type_archive( 'event' ) ) {
return;
}
$query->set( 'meta_query', array(
'event_date' => array(
'key' => '_event_date',
'value' => current_time( 'Y-m-d' ),
'compare' => '>=',
'type' => 'DATE',
),
) );
$query->set( 'orderby', 'event_date' );
$query->set( 'order', 'ASC' );
} );
meta_queryの条件にキー(ここではevent_date)を付けると、orderbyにそのキーを指定して並べ替えられます。- 今日の日付は
current_time( 'Y-m-d' )で取ります。WordPress は PHP のタイムゾーンを UTC にしているため、date()では日本時間の午前0時から9時の間に前日の日付になります。current_time()は「設定」→「一般」のタイムゾーンに合わせた日付を返します。 - この条件では、
_event_dateが空の投稿は表示されません。
pre_get_postsが向かない場面
- 固定ページや個別投稿の表示を、別の一覧に変える: 開発者リファレンスでは、個別の投稿や固定ページのクエリを、投稿のアーカイブのクエリに変えることはできないとされています。固定ページの中に一覧を出したいときは、テンプレートで
WP_Queryを使います。 - トップページに固定ページを使っている場合の判定: この時点では
is_front_page()が正しく動かないため、条件に使わないでください。 - ページ送りと
offsetの併用:offsetを指定すると、ページ送りが壊れます。直し方は WordPressのページネーションが404になる原因とpre_get_postsでの直し方 で説明しています。
動作を確かめる
- 変更したページの種類(ブログのトップ、カテゴリー、検索結果など)をそれぞれ開き、件数と並び順を確かめます。
- 2ページ目と最後のページを開き、404にならないことを確かめます。
- 管理画面の「投稿」→「投稿一覧」の件数と並び順が変わっていないことを確かめます。
- ウィジェットやブロックの「最新の投稿」など、ほかの一覧が変わっていないことを確かめます。
PHP の構文エラーがあるとサイトが表示されなくなることがあります。問題が起きたら、FTP やファイルマネージャーで追加したコードを削除してください。
まとめ
pre_get_postsは、すべてのWP_Queryで実行される。is_admin()と$query->is_main_query()で、表側のメインクエリだけに絞る。- 条件分岐は
$query->is_home()などのメソッド版を使う。is_front_page()はこの時点では使えない。 $query->set()で、posts_per_page・category__not_in・meta_query・orderbyなどWP_Queryの引数を変えられる。- 固定ページや個別投稿のクエリを一覧に変える用途には使えない。その場合はテンプレートで
WP_Queryを使う。