WordPressを使うなら知っておきたいpre_get_postsの仕組みと使い方

WordPressで定番のテンプレートタグだったquery_postsが非推奨となり、代わりにpre_get_postsを使う流れになりましたが、正しく使えていますか?
pre_get_postsの仕組みや使い方がわからない方に、この記事が理解の手助けになればと思います。

メインクエリについて理解しよう

まずpre_get_postsの仕組みを理解するのにはメインクエリという言葉を知っておく必要があります。
メインクエリとは、WordPressがウェブページを表示するときデータベースにアクセスして記事データを格納しているオブジェクトのことです。
メインクエリは投稿ページ・固定ページ・アーカイブページなどのページを表示する際に、表示するページに合った記事データを格納しています。
例えば投稿の詳細ページでその記事情報をwhile文だけで呼び出すことができるのは、メインクエリに投稿した記事データが格納されているからです。
同様にアーカイブページではメインクエリに投稿の記事一覧が格納されているため、while文だけですべての投稿を呼び出すことができます。
while文とは一般的な下記コードのことを指しています。

// 記事を取得できたら
if ( have_posts() ) {
  // 記事の数だけ繰り返す
  while ( have_posts() ) {
    the_post();
    
    // 繰り返す処理を書く
  }
}

query_postsの問題点

これは一般的なquery_postsの記述例です。

query_posts( 'cat=1' );

// カテゴリーIDが1の記事を取得できたら
if ( have_posts() ) {
  // カテゴリーIDが1の記事の数だけ繰り返す
  while ( have_posts() ) {
    the_post();
    
    // 繰り返す処理を書く
  }
}

このquery_postsを使った方法はメインクエリを直接書き換えてしまうため、他のページのメインクエリに影響を及ぼしたり、ページング処理の動作に問題が合ったり、バグが発生しやすくとても不安定です。
WordPressの公式マニュアルでも「決して使うべきではない」と記載がある通り、今後は使わないようにしましょう。

pre_get_postsの使い方

query_postsの危険性も理解したところで、pre_get_postsの具体的な使い方について説明します。
呼び出されるテンプレートファイルに直接記述したquery_postsとは違い、pre_get_postsはfunctions.phpにまとめて記述します。
1箇所でメインクエリを管理できるので見やすくなるので、メンテナンスがしやすくなるというメリットもあります。
基本の書き方は下記です。

function my_posts_control( $query ) {
  if ( is_admin() || ! $query->is_main_query() ) {
    return;
  }

  // 条件
}
add_action( 'pre_get_posts', 'my_posts_control' );

pre_get_queryは管理画面やメインクエリ以外も操作できてしまうので影響が出ないように、最初のif文は必ず入れましょう。
コメント文にある「// 条件」の部分に、どのページのどんなルールで記事を呼び出すかを記述します。
例えば、もしアーカイブページだったら1ページあたり5件ずつ取得する、というルールの場合はこうです。

function my_posts_control( $query ) {
  if ( is_admin() || ! $query->is_main_query() ) {
    return;
  }

  if ( $query->is_archive() ) {
    $query->set( 'posts_per_page', '5' );
    return;
  }

}
add_action( 'pre_get_posts', 'my_posts_control' );

もう少し複雑な例をあげてみましょう。

function my_posts_control( $query ) {
  if ( is_admin() || ! $query->is_main_query() ) {
    return;
  }

  if ( $query->is_post_type_archive( 'event' ) ) {
    $query->set( 'orderby', 'meta_value' );
    $query->set( 'meta_key', '開催日' );
    $query->set( 'order', 'ASC' );

    return;
  }
}
add_action( 'pre_get_posts', 'my_posts_control' );

これはカスタム投稿(event)でカスタムフィールドの開催日を昇順で取得しています。
条件の書き方はget_posts()とほとんど同じなので簡単ですね。
カスタム投稿(event)で「本日以降」の記事を取得したい場合の例も見ていきましょう。

function my_posts_control( $query ) {
  if ( is_admin() || ! $query->is_main_query() ) {
    return;
  }

  if ( $query->is_post_type_archive( 'event' ) ) {
    $meta_query = [
      [
        'key'     => '開催日',
        'value'   => date( 'Y-m-d' ),
        'compare' => '>=',
        'type'    => 'DATE'
      ]
    ];
    $query->set( 'meta_query', $meta_query );

    return;
  }
}
add_action( 'pre_get_posts', 'my_posts_control' );

最後に

pre_get_postsの仕組みや使い方について、イメージは掴めましたか?
完全に理解できていなくても使っていくうちに身に付いていくと思いますので、焦らずに頑張ってください。
あとは実際に使ってみるとき、WordPressの公式マニュアルを参考にしながら覚えていきましょう。

SNSでシェアする:

大場 正樹 / Cleysense株式会社 代表

Web制作会社に3年勤務した後にフリーランスとしてWeb制作やWebマーケティングなどの事業で6年活動し、事業拡大に伴い2019年7月にCleysense株式会社を設立。