【WordPress実践】pre_get_postsで記事一覧の表示条件を安全に変更する方法と活用パターン集

WordPress

WordPressで「トップページの記事数を変えたい」「特定カテゴリーだけ非表示にしたい」など、投稿の表示条件をカスタマイズしたい場面は多いです。

ですが、query_posts() を使って直接メインクエリを書き換えると、ページネーションが壊れたり、他のテンプレートに影響したりとトラブルの原因になることもあります…。

そんなときに安全に条件を変更できるのが pre_get_posts フック です。

この記事では、pre_get_posts の基本的な使い方から、トップページ・カテゴリー別・カスタム投稿タイプなどの実践パターンまで、現場で役立つ設定例をまとめて紹介します。

テーマの改修やサイト制作で「正しく条件を制御したい」ときに、すぐ使えるリファレンスとして活用してください。

pre_get_postsとは?基本の仕組み

pre_get_posts は、WordPressがデータベースから投稿を取得する前(pre)に、メインクエリの条件を変更できるアクションフック です。
簡単に言うと、「投稿一覧を取得する直前に、表示条件を安全にカスタマイズできる仕組み」です。

「メインクエリ」を安全に書き換える方法

WordPressのページが表示されるとき、内部では「どの記事を表示するか」を決める メインクエリ が自動で生成されます。
query_posts() を使うとこのメインクエリを“強制的に上書き”してしまうため、ページネーションが壊れたり、他のテンプレートに影響が及ぶことがあります。

一方で、pre_get_postsクエリが実行される前に条件を「調整」するだけ なので、安全かつ確実に動作します。
テーマ制作やカスタマイズでは、この方法が推奨されています。

管理画面にも影響するため条件分岐が必須

pre_get_posts管理画面(wp-admin)でも発火する ため、フック内で無条件にクエリを変更すると、投稿一覧画面やメディア一覧まで影響してしまいます。

そのため、以下のように !is_admin()$query->is_main_query() をセットで使うのが基本です。

function my_modify_main_query($query) {
  // 管理画面ではなく、かつメインクエリのときのみ実行
  if ( !is_admin() && $query->is_main_query() ) {
    // 条件を変更
  }
}
add_action('pre_get_posts', 'my_modify_main_query');
  • !is_admin() … 管理画面での実行を除外する
  • $query->is_main_query() … メインクエリのみを対象にする(サブループには影響しない)
どんな時に使う?
  • トップページで記事数を変更したい
  • 特定のカテゴリーを除外したい
  • カスタム投稿タイプを同時に表示したい
  • 検索結果にカスタム投稿も含めたい

このような「一覧の取得条件をテーマ全体で変更したい」ときに最適です。
次のセクションでは、実際に使える条件設定パターンを紹介していきます。

pre_get_postsの条件設定パターン集

pre_get_posts は、トップページ・カテゴリー・検索結果など、WordPressの表示条件ごとに柔軟な調整ができます。
ここでは、よく使われるパターンを5つ紹介します。

パターン1:トップページの記事数を変更する

トップページ(ブログ一覧)だけ表示件数を変更したい場合のコードです。

function my_modify_main_query($query) {
  if ( !is_admin() && $query->is_main_query() && is_home() ) {
    // トップページの記事を6件に設定
    $query->set('posts_per_page', 6);
  }
}
add_action('pre_get_posts', 'my_modify_main_query');
ポイント
  • is_home() … 投稿一覧(トップページ)だけを対象に。
  • テーマのsettings > 表示設定の値を上書きできる。
  • ignore_sticky_postscategory__not_inも併用可能。

パターン2:特定のカテゴリーを除外する

トップページやアーカイブで、特定のカテゴリーを非表示にしたいときの例です。

function exclude_category_from_home($query) {
  if ( !is_admin() && $query->is_main_query() && is_home() ) {
    // IDが3のカテゴリーを除外
    $query->set('cat', '-3');
  }
}
add_action('pre_get_posts', 'exclude_category_from_home');
ポイント
  • catパラメータにマイナス値を指定すると除外できる。
  • 複数除外したい場合:$query->set('cat', '-3,-5,-7');
  • 特定カテゴリーのみ表示したい場合はプラス値に変更。

パターン3:カスタム投稿タイプを追加で表示する

トップページなどで、通常の投稿+カスタム投稿(例:お知らせ)をまとめて表示したいとき。

function add_custom_post_to_home($query) {
  if ( !is_admin() && $query->is_main_query() && is_home() ) {
    // 投稿タイプ「post」と「news」を同時に表示
    $query->set('post_type', array('post', 'news'));
  }
}
add_action('pre_get_posts', 'add_custom_post_to_home');
ポイント
  • post_typeに配列を指定すると複数の投稿タイプを同時に扱える。
  • カスタム投稿をトップに混ぜたいときに便利。
  • 並び順を指定したい場合は $query->set('orderby', 'date'); などを追加。

パターン4:検索結果にカスタム投稿を含める

検索機能で、投稿タイプ「post」だけでなく「news」や「event」も対象にしたい場合。

function extend_search_to_custom_post($query) {
  if ( !is_admin() && $query->is_main_query() && $query->is_search() ) {
    // 検索対象を追加
    $query->set('post_type', array('post', 'news', 'event'));
  }
}
add_action('pre_get_posts', 'extend_search_to_custom_post');
ポイント
  • $query->is_search() は検索結果ページ専用。
  • カスタム投稿も検索対象に含めたいときは必須。
  • 逆に除外したい場合は、post_typeから削除するだけでOK。

パターン5:特定のカスタム投稿アーカイブで並び順を変更

カスタム投稿タイプの一覧ページ(例:event)で、カスタムフィールドの日付順に並び替える例です。

function sort_event_by_date($query) {
  if ( !is_admin() && $query->is_main_query() && is_post_type_archive('event') ) {
    $query->set('meta_key', 'event_date'); // フィールド名
    $query->set('orderby', 'meta_value');
    $query->set('order', 'ASC'); // 昇順
  }
}
add_action('pre_get_posts', 'sort_event_by_date');
ポイント
  • meta_keyでカスタムフィールドを指定。
  • 日付順や価格順など、柔軟な並び替えが可能。
  • フィールドが日付型ならmeta_typeDATEにするのもおすすめ。

まとめ:条件分岐で制御すれば安心

pre_get_postsは非常に強力なフックですが、「管理画面を除外」し、「メインクエリのみ対象」とするのが鉄則です。

条件関数
管理画面以外!is_admin()
メインクエリだけ$query->is_main_query()
トップページis_home()
カテゴリー一覧is_category()
カスタム投稿アーカイブis_post_type_archive('slug')

pre_get_postsのよくある失敗例

便利なpre_get_postsですが、条件を誤ると管理画面まで影響したり、意図しない投稿が消えることがあります。
ここでは、実務でも起きがちな失敗例と、その回避方法を紹介します。

1. 管理画面にも影響してしまう

function my_modify_main_query($query) {
  if ( $query->is_main_query() ) {
    $query->set('posts_per_page', 5);
  }
}
add_action('pre_get_posts', 'my_modify_main_query');

上記のように!is_admin()を忘れると、投稿一覧(管理画面)にも反映されてしまいます。
管理画面の表示件数が変わったり、一覧が壊れる原因になります。

正しくはこう書く

if ( !is_admin() && $query->is_main_query() ) {
  $query->set('posts_per_page', 5);
}

2. メインクエリ以外に影響を与えてしまう

$query->is_main_query()を入れずに書くと、ウィジェットやサブループ(WP_Queryなど)のクエリまで変更されてしまいます。

ポイント

メインクエリのみ変更したい」なら$query->is_main_query()を必ず条件に入れる。

3. 条件分岐の位置を間違える

is_home()is_category()などの条件を、
if ( !is_admin() && $query->is_main_query() )外側に書いてしまうケースもよくあります。

悪い例

if ( is_home() ) {
  if ( !is_admin() && $query->is_main_query() ) {
    $query->set('posts_per_page', 5);
  }
}

この書き方では、is_home()がfalseの時点で処理が止まるため、WordPressの初期化段階で正しく判定できないことがあります。

正しい書き方

function my_modify_main_query($query) {
  if ( !is_admin() && $query->is_main_query() ) {
    if ( is_home() ) {
      $query->set('posts_per_page', 5);
    }
  }
}
add_action('pre_get_posts', 'my_modify_main_query');

4. 条件を複数書いて混乱する

複数の条件(例:トップページとカスタム投稿)をまとめて書くと、どのページでどの条件が効いているのか分からなくなることも。

ポイント

用途ごとに関数を分けると、デバッグや改修が楽になります。

add_action('pre_get_posts', 'modify_home_query');
add_action('pre_get_posts', 'modify_custom_post_query');

まとめ:失敗しないための3原則

チェック項目内容
!is_admin() を忘れない管理画面への影響を防ぐ
$query->is_main_query() を必ず使うサブループを壊さない
条件分岐を関数内に書く正しいタイミングで判定させる

まとめ

pre_get_postsは、WordPressで「安全にメインクエリをカスタマイズできる」非常に強力なフックです。
!is_admin() と $query->is_main_query() の条件を正しく使えば、管理画面やサブループへの影響を避けながら、トップページ・カテゴリー・カスタム投稿などの表示を自在にコントロールできます。

query_posts()のように無理やり書き換えるのではなく、「WordPressが投稿を取得する前に調整する」――この考え方が安定したサイト運用につながります。

まずはシンプルな条件変更から試して、徐々に複数条件や並び替えなどへ発展させていきましょう。

この記事を書いた人
管理人

2012年にWebデザインの勉強を始め、2013年より制作会社に勤務。
これまでに500件以上のWebサイト制作・運用に携わってきました。
現在も制作会社に勤務しながら、Webデザインスクールのトレーナーとしても後進の育成に取り組んでいます。
WordPressやデザインの実践的なノウハウを、初心者にもわかりやすく発信できるよう試行錯誤しています。

管理人をフォローする
WordPress
スポンサーリンク
管理人をフォローする

コメント

タイトルとURLをコピーしました