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での直し方 で説明しています。

動作を確かめる

  1. 変更したページの種類(ブログのトップ、カテゴリー、検索結果など)をそれぞれ開き、件数と並び順を確かめます。
  2. 2ページ目と最後のページを開き、404にならないことを確かめます。
  3. 管理画面の「投稿」→「投稿一覧」の件数と並び順が変わっていないことを確かめます。
  4. ウィジェットやブロックの「最新の投稿」など、ほかの一覧が変わっていないことを確かめます。

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 を使う。

お気軽にご相談ください

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