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_postsやcategory__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_typeをDATEにするのもおすすめ。
まとめ:条件分岐で制御すれば安心
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が投稿を取得する前に調整する」――この考え方が安定したサイト運用につながります。
まずはシンプルな条件変更から試して、徐々に複数条件や並び替えなどへ発展させていきましょう。



コメント