3.3の新しい関数 is_main_query を使おう

WordPressの3.3で、新しい関数 is_main_query が使えるようになりました。
WordPress をカスタマイズをガッツリ行う方には、是非知っておいていただきたいものです。
といっても、有用なのは関数ではなく、クラスメソッドの方ではありますが。。

表示カスタマイズ方法のおさらい

例えば、カテゴリーアーカイブだったら表示する件数を5件にしたい時や、年月アーカイブでは特定のカテゴリーを除きたい時などどうしていますか?
簡単にやるのであれば query_posts を使い、その条件で記事を取得する方法ですが、これは、データベースへのアクセスが増えるので、パフォーマンス的にはあまりおすすめできません。速くするためにCSSスプライトを使ったりするのに、これではちょっと本末転倒な気もしますよね。

一番いいのは、WordPress が標準で表示する記事の条件を状況に応じて変更してあげて、デフォルトで表示するものそのものを変えてあげる方法です。方法は意外と簡単で pre_get_posts フックで、引数で渡されてくるオブジェクトを、ちょろっと変えてあげるだけで実現できたりします。

CODE 1 カテゴリーアーカイブだったら表示する件数を5件にする

function category_display_five_articles( $wp_query ) {
	if ( $wp_query->is_category() ) {
		$wp_query->set( 'posts_per_page', 5 );
	}
}
add_action( 'pre_get_posts', 'category_display_five_articles' );

CODE 2 年月アーカイブでは未分類を表示しない
※ 404になる場合があるので注意!

function date_archive_exclude_uncategorize( $wp_query ) {
	if ( $wp_query->is_date() ) {
		$wp_query->set( 'cat', -1 );
	}
}
add_action( 'pre_get_posts', 'date_archive_exclude_uncategorize' );

is_main_queryの使い方

で、ここで、ようやく本題に戻ってきます。WordPress では、標準で表示する記事の他に、関連記事や最新情報などの取得に query_posts や get_posts が使われたり、その他にもナビゲーションメニュー機能を利用している場合は、このメニューデータの取得にも get_posts が利用されています。
CODE 1CODE 2のフックは、標準の記事取得以外の query_posts や get_posts にも効いてしまうため、状況によっては想定と違う結果が出てしまったりして、ドツボにはまりかねません。
そんなとき、WordPress の標準のクエリーか、テンプレートから呼び出されたのかを判別するのが、 is_main_query というわけです。
先のCODE 1CODE 2を、is_main_query を用いて書き直すと、

CODE 3 カテゴリーアーカイブだったら表示する件数を5件にする

function category_display_five_articles( $wp_query ) {
	if ( $wp_query->is_main_query() && $wp_query->is_category() ) {
		$wp_query->set( 'posts_per_page', 5 );
	}
}
add_action( 'pre_get_posts', 'category_display_five_articles' );

CODE 4 年月アーカイブでは未分類を表示しない
※ 404になる場合があるので注意!

function date_archive_exclude_uncategorize( $wp_query ) {
	if ( $wp_query->is_main_query() && $wp_query->is_date() ) {
		$wp_query->set( 'cat', -1 );
	}
}
add_action( 'pre_get_posts', 'date_archive_exclude_uncategorize' );

となり、他に影響を与えなくなります。

3.2以下の場合

3.3未満の場合は、どうすりゃいいの?という話ですが、 is_main_query メソッドの中身は単純で、

	function is_main_query() {
		global $wp_the_query;
		return $wp_the_query === $this;
	}

と、オブジェクトの同一比較を行っているだけだったりします。

つまり、ちょっとだけ記述が増えますが、is_main_query が使えないバージョンでは、

CODE 5 WordPress 3.2 でカテゴリーアーカイブだったら表示する件数を5件にする

function category_display_five_articles( $wp_query ) {
	global $wp_the_query;
	if ( ( $wp_the_query === $wp_query ) && $wp_query->is_category() ) {
		$wp_query->set( 'posts_per_page', 5 );
	}
}
add_action( 'pre_get_posts', 'category_display_five_articles' );

のように書けば古いバージョンでもバグが起こりにくい記述をすることができますね。