先日、WordPress で投稿者アーカイブなど不要なページを 404 にする記事を書いたときに pre_get_posts が出てきたので、自分の復習も兼て pre_get_posts について簡単にまとめてみた。
まず基本の使い方
例えば、トップページの表示件数は6件、カテゴリーページの表示件数10件とかにする場合は functions.php に次のようにして pre_get_posts のアクションフックを使う
functions custom_pre_get_posts( $query ) {
if ( is_admin() )
return;
if ( $query->is_home() && $query->is_main_query() ) {
$query->set( 'posts_per_page', 6 );
return;
}
if ( $query->is_category() && $query->is_main_query() ) {
$query->set( 'posts_per_page', 10 );
return;
}
}
add_action('pre_get_posts', 'custom_pre_get_posts');
とする。ちょっと基本的なことから解説すると、2箇所出てくる custom_pre_get_posts というのは自分で好きにつけてよい(もちろん2箇所とも同じにしなければならない)。
それで最初の
if ( is_admin() )
return;
は管理画面に影響を及ばさないための対処。WordPress の表側だけで色々な設定していきますよ、ということ。
それで if ( $query->is_category() && $query->is_main_query() ) の $query->is_main_query() が重要。これでメインクエリに対して、$query->set( ‘posts_per_page’, 10 ) ってのが適用される。
メインクエリって何? って感じだけど、カテゴリーページなら記事一覧の記事データをデータベースから取得してくる条件みたいなものだ。
要は index.php とか category.php とかに
<?php if ( have_posts() ) : ?>
<?php while ( have_posts() ) : the_post(); ?>
<article>
<h2><?php the_title(); ?></h2>
<?php the_excerpt(); ?>
</article>
<?php endwhile; ?>
<?php endif; ?>
なんてあるループのところに上記の設定 $query->set( ‘posts_per_page’, 6 ) とかを適用しますよってことになる。
逆に if 条件に $query->is_main_query() をつけないとメインじゃないループ、たとえばサイドバーとかの新着記事とかに影響を及ぼすことがある。
ほかには特定のカテゴリーを除外したり
上記の例は表示する記事件数を指定する例だったけど、トップページの新着記事にはあるカテゴリーの記事は表示させたくない場合。
たとえばカテゴリーIDが 3 と 5 のカテゴリーの投稿を表示させたくない場合は
functions custom_pre_get_posts( $query ) {
if ( is_admin() )
return;
if ( $query->is_home() && $query->is_main_query() ) {
$query->set( 'category__not_in', array( 3, 5 ) );
return;
}
}
add_action('pre_get_posts', 'custom_pre_get_posts');
なんてすればよい。
それとか、特定の投稿を除外したい場合、たとえば投稿 ID が 20 と 51 の投稿を除外したい場合は
functions custom_pre_get_posts( $query ) {
if ( is_admin() )
return;
if ( $query->is_home() && $query->is_main_query() ) {
$query->set( 'post__not_in', array( 20, 51 ) );
return;
}
}
add_action('pre_get_posts', 'custom_pre_get_posts');
とする。
複数のループを入れたいんだけど、っていう場合
上みたいにやれば記事一覧のループに対していろいろ指定できるのはわかったけど、それとは別のループを入れたいんだけど、という場合。たとえば
新着記事
・新着記事1
・新着記事2
・新着記事3
「ほげ」カテゴリーの新着
・ほげ記事1
・ほげ記事2
・ほげ記事3
ってしたい場合。新着記事のほうは
<?php if ( have_posts() ) : ?>
<h2>最新記事</h2>
<?php while ( have_posts() ) : the_post(); ?>
<article>
<h3><?php the_title(); ?></h3>
<?php the_excerpt(); ?>
</article>
<?php endwhile; ?>
<?php endif; ?>
とメインのループで表示させ、表示させる件数などは上のように pre_get_posts のアクションフックで対応すればよい。
対して「ほげ」カテゴリーの新着のほうは、メインクエリとは別のクエリを生成してやる。
そのためには new WP_Query を使う。「ほげ」カテゴリーのスラッグが hoge なら
$args = array(
'posts_per_page' => 3,
'category_name' => 'hoge',
);
$the_query = new WP_Query( $args );
<?php if ( $the_query->have_posts() ) : ?>
<h2>「ほげ」カテゴリーの新着</h2>
<?php while ( $the_query->have_posts() ) : $the_query->the_post(); ?>
<article>
<h2><?php the_title(); ?></h2>
<?php the_excerpt(); ?>
</article>
<?php endwhile; wp_reset_postdata(); ?>
<?php endif; ?>
としてやれば、「ほげ」カテゴリーの新着記事が 3 件表示される。
$the_query = new WP_Query( $args );
の一行で、メインクエリとは別のクエリを生成している。そのクエリの諸条件を $args の配列で指定しているわけど。
ループのほうのポイントはメインループのほうでは単に have_posts() とかなっているのが $the_query->have_posts() とかなっているところ。
これで $the_query = new WP_Query( $args ) で生成したクエリのことを扱うことができる。($the_query は好きに決めれて $my_query とか $query とか、さらにいくつか使用する場合は、 $the_query01、 $the_query02…とかでオッケー)
さらに重要なのが endwhile; の後の wp_reset_postdata(); 。これは new WP_Query を使ったクエリを実行した後で、もとメインクエリに戻すために必要。
これが無いと、これ以降 new WP_Query を使ったクエリの影響が続いてしまう。
それで他にどんな条件を指定できるの?
表示させる件数や特定の記事の除外とかを上で紹介したけど、他にも色々使える。あんまりにも色々使えるので下記を参照してください。
WordPress Codex 日本語版 「関数リファレンス/WP Query」
のページにある「~パラメータ」で紹介されているのが使えます。このページでは new WP_Query で使う例が紹介されているけど、たとえば
$args = array(
'date_query' => array(
array(
'year' => 2012,
'month' => 12,
'day' => 12,
),
),
);
$query = new WP_Query( $args );
という2012年12月12日の投稿を取ってくるという例の場合。それをメインクエリを変更するpre_get_posts のアクションフック内で使うのであれば
if ( $query->is_home() && $query->is_main_query() ) {
$query->set( 'date_query', array(
array(
'year' => 2012,
'month' => 12,
'day' => 12,
),
) );
}
と、とにかく $query->set( ‘……’, ‘……’ ) の形にすればよい。
とざっと pre_get_posts のアクションフックと、メインのループとは別のループを使う場合についてまとめてみました。