ワードプレスでメインクエリの検索条件をカスタマイズする方法

ワードプレスでメインクエリの検索条件をカスタマイズするには、functions.phpまたはfunctions.phpから読み込まれるPHPファイルに以下のようなコードを追加します。

// =====================================================
// メインクエリのカスタマイズ
// =====================================================
function custom_pre_get_posts($query) {
  // 管理画面内のクエリまたはサブクエリの場合は何も変更しない。
  if (is_admin() || !$query->is_main_query()){
    return;
  }

  // ブログ投稿インデックスの1ページあたり最大表示件数を20件に変更する。
  if ($query->is_home() && !$query->is_front_page()) {
    $query->set('posts_per_page', 20);
    return;
  }
}
add_action( 'pre_get_posts', 'custom_pre_get_posts' );

コードの解説

【16行目】
ワードプレスで記事データを表示するための検索処理が実行されるとき、pre_get_postsと名付けられたポイントを通過します。正確には、検索処理が実行される直前で、これから行う検索の条件を準備し終わったタイミングです。ここに、検索条件をカスタマイズするために自分で作成するPHP関数の名前を2つ目のパラメータに指定します。この例では、custom_pre_get_postsという関数名にしました。

【4行目】
pre_get_postsにフックさせた関数には、ワードプレスが設定し終えた検索条件などが詰め込まれたWP_Queryオブジェクトが引き渡されます。ここでは、WP_Queryオブジェクトを受け取る変数に$queryという名前を付けました。もしcustom_pre_get_posts関数の中で、$queryに何も変更を加えなければ、メインクエリの動作は変わりません。

【6-7行目】
is_admin()は、今まさにこのコードがどの画面(ページ)で実行されているのかを判定するワードプレスの関数で、管理画面ならばtrue、管理画面でなければfalseを返します。is_main_query()は、WP_Queryオブジェクトが持っているメソッドで、今まさに実行されようとしているクエリ(検索処理のこと)がメインクエリかどうかを判定するワードプレスの関数で、メインクエリならtrue、メインクエリでなければfalseを返します。

つまり、ここでは「管理画面内で行われるさまざまな検索処理」または「公開ページ側のテンプレートや、記事データを表示するようなプラグイン内で行われるサブクエリ」の場合には以降の変更処理を実行させないように、すぐにreturnで関数を終了しています。

【11行目】
本当に変更を行いたいのは、ブブログ投稿インデックスのメインクエリが実行されようとしているタイミングです。これをif文の条件式で表すとis_home()trueを返し、なおかつis_front_page()falseを返す場合、ということになります。

【12行目】
set()WP_Queryオブジェクトが持つメソッドで、1つ目のパラメータに指定した検索条件に、2つ目のパラメータに指定した値を設定する(setする)役目をします。posts_per_pageは1ページあたりの投稿数を表す検索条件です。このパラメータに20を設定すれば、1ページあたりの最大表示件数が20件に変わります。

【13行目】
12行目でWP_Queryオブジェクトに検索条件の変更を伝え終わったので、returnで関数を終了します。

特定のカテゴリーに属する記事だけを検索結果から除外する

名前がレビューでスラッグがreviewのカテゴリーと、名前がお客様の声でスラッグがvoiceのカテゴリーに属する投稿をブログ投稿インデックスに表示されないようにするには、以下のようにします。

// =====================================================
// メインクエリのカスタマイズ
// =====================================================
function custom_pre_get_posts($query) {
  // 管理画面内のクエリまたはサブクエリの場合は何も変更しない。
  if (is_admin() || !$query->is_main_query()){
    return;
  }

  // ブログ投稿インデックスの検索条件を変更する。
  if ($query->is_home() && !$query->is_front_page()) {
    $cat_not_in = array();
    $cat_not_in[] = get_category_by_slug('review')->cat_ID;   // 「レビュー」のカテゴリーの記事を除外する
    $cat_not_in[] = get_category_by_slug('voice')->cat_ID;    // 「お客様の声」のカテゴリーの記事を除外する
    $query->set('category__not_in', $cat_not_in);
    return;
  }
}
add_action( 'pre_get_posts', 'custom_pre_get_posts' );

【13-14行目】
get_category_by_slug()は、パラメータに指定したスラッグを持つカテゴリーオブジェクトを返すワードプレスの関数です。関数がオブジェクトを返す場合、関数を呼び出した箇所にオブジェクトがそのまま当てはまるので、アロー演算子->でカテゴリーオブジェクトのプロパティを引っ張り出すことができます。cat_IDはカテゴリーオブジェクトが持つプロパティで、カテゴリーのIDが格納されています。これを、$cat_not_inと名付けた配列(除外したいカテゴリーのIDをまとめて格納するための配列)に積み込みます。

【15行目】
category__not_inは、その名の通り、2つ目のパラメータに指定するカテゴリーIDを含まない(not in)という条件を表すパラメータです。

CODEXでWP_Queryオブジェクトの解説ページを読むと、ワードプレスで記事データの取得条件をどのように変更すればよいか、コツがつかめるのではないかと思います。