この記事は最後に更新してから1年以上経過しています。

もうquery_postsは呼ばない

説明

トップページやカテゴリーページで標準の条件に少し手を加えた投稿情報を表示するケースがある。そんな時、テンプレートファイルの先頭で query_posts関数を呼び出して投稿情報を再抽出していたのだが、フィルター処理をうまく使えばquery_posts関数を呼び出さなくても大丈夫みたいだ。
そもそもなぜこんなことを考えたかというと、テンプレートファイルの先頭でquery_posts関数の呼び出しは、それなりに時間がかかっているから。WordPressのシステム自体が最初に投稿情報を抽出する際に条件を変更できれば、query_posts関数の呼び出しも必要なくなり、結果としてページを表示するまでの時間も短縮できることになる。

query_postsのフィルター

WordPressのフィルター処理は特定の関数の結果に影響を与えるもので、query_posts関数には多くのフィルターが用意されている。使用頻度が高い(比較的使い勝手がいい?)と思われるフィルターには次のようなものがある。
フィルター意味
posts_joinJOINの指定
posts_whereWHEREの指定
posts_groupbyGROUP BYの指定
posts_orderbyORDER BYの指定
post_limitsLIMITの指定
posts_fields抽出カラムの指定
これらは投稿情報を抽出するSQL文を構成するパーツに対応しており、SQLについて知識がある方ならそれぞれが何なのか想像できるだろう。

トップページに表示する投稿情報数を変える

具体例があった方がピンくると思うので、トップページ(フロントページ)に表示する投稿情報の件数を変更する例を最初に紹介する(各ソースコードは、原則自身のテーマのfunctions.phpに記載するものとし、各関数名mythemeの部分の部分は適宜変更するものとして読み進めてほしい)。
まずquery_posts関数を呼び出す場合は次の指定になる。
query_posts( 'posts_per_page=5' );
これをフィルターで対応する場合は、次のように指定すればいい。
add_action( 'after_setup_theme', 'mytheme_setup' );

function tpsalon_setup() {
	add_filter( 'post_limits', 'mytheme_post_limits' );
}

function mytheme_post_limits( $arg ) {
	global $wp_query;
	if ( $wp_query->is_home ) {
		$arg = 'LIMIT 0, 5';
	}
	remove_filter( 'post_limits', __FUNCTION__ );
	return $arg;
}
流れを簡単に説明すると、
1.after_setup_themeアクションの処理としてquery_posts関数のフィルターであるpost_limitsフィルターとしてmytheme_post_limits関数を登録。
2.WordPressシステムが最初にquery_posts関数を呼び出した際に、登録したmytheme_post_limits関数が呼び出される。
3.mytheme_post_limits関数では、グローバル変数$wp_queryを参照して呼び出しがトップページか調べ、トップページの場合はパラメータ$argの内容を'LIMIT 0, 5'(先頭から5件のみ取得)に変更。
4.誤動作を防ぐため、フィルターからmytheme_post_limits関数を削除。
5.パラメータ$argを返す。
といった流れになる。
mytheme_post_limits関数のパラメータ$argには「表示設定」の「1ページに表示する最大投稿数」で指定した値(デフォルトであれば10)を含んだ文字列('LIMIT 0,10')が格納されており、ここではトップページの場合のみ5件に変更していることになる。なおグローバル変数$wp_queryは、query_posts関数の呼び出しによって生成・更新されるWP_Queryのオブジェクトで、is_homeプロパティは呼び出しがトップページかどうかを示している。この値は is_home関数で取得できるものと同じである。

日付アーカイブページの表示順を昇順にする

今度は日付アーカイブページで投稿情報が表示する順番を投稿日時の新しい順から古い順に変更してみる。
まずquery_posts関数を呼び出す場合は次の指定になる。
query_posts( 'order=ASC' );
これをフィルターで対応する場合は、次のように指定すればいい。
add_action( 'after_setup_theme', 'mytheme_setup' );

function tpsalon_setup() {
	add_filter( 'posts_orderby', 'mytheme_posts_orderby' );
}

function mytheme_posts_orderby( $arg ) {
	global $wp_query;
	if ( $wp_query->is_date ) {
		$arg = str_replace( 'DESC', 'ASC', $arg );
	}
	remove_filter( 'posts_orderby', __FUNCTION__ );
	return $arg;
}
流れを説明すると、
1.after_setup_themeアクションの処理としてquery_posts関数のフィルターであるposts_orderbyフィルターとしてmytheme_posts_orderby関数を登録。
2.WordPressシステムが最初にquery_posts関数を呼び出した際に、登録したmytheme_posts_orderby関数が呼び出される。
3.mytheme_post_limits関数では、グローバル変数$wp_queryを参照して呼び出しが日付アーカイブページか調べ、日付アーカイブページの場合はパラメータ$argの中身の'DESC'を'ASC'に変更。
4.誤動作を防ぐため、フィルターからmytheme_posts_orderby関数を削除。
5.パラメータ$argを返す。
といった流れになる。基本的な流れは先ほどと同じで、ここではstr_replaceによってパラメータ$argの内容を更新している。ちなみに呼び出し時点の$argの内容は'wp_posts.post_date DESC'となっている('wp_'の部分はWordPressをインストールした際のプレフィックスによって変わる)。

フィルターの使いこなしにはSQLの知識が欠かせない

ここまで簡単な使用例を2つ紹介した。各テンプレートファイルでquery_posts関数を呼び出した方が簡単なのは確かだが、より効率よくリクエストされたページを表示するならquery_posts関数のフィルターで対応するほうが望ましいと考える。
query_posts関数のフィルターを使いこなすにはSQLの知識も欠かせない。それはより実践的なシーンでは、いくつかのフィルターを組み合わせることになるからだ。というわけで、次回は他のフィルターや複数のフィルターを組み合わせについて紹介してみたい(需要があるか不安ではあるが)。

最終更新 : 2011年09月27日 20:56


お勧め

parse_blocks(2024年7月24日 更新)

array[] parse_blocks( string $content )
投稿コンテンツをパースする。

single_post_title(2012年9月6日 更新)

string single_post_title( [ string $prefix = '' [ , bool $display = true ] ] )
投稿ページのタイトルを表示する。

timer_stop(2021年7月23日 更新)

string timer_stop( [ int $display = 0 [ , int $precision = 3 ] ] )
タイマー開始時からの経過時間を取得する。

is_ssl(2022年7月2日 更新)

bool is_ssl( )
リクエストがSSLかどうか調べる。

wp_title_rss(2014年4月10日 更新)

void wp_title_rss( [ string $sep = '»' ] )
フィード向けのページタイトルを出力する。