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

query_posts(WP_Queryクラス)でカスタムフィールドを使う

説明

先週3回にわたってtax_queryパラメータを使ったカテゴリーや投稿タグ、投稿フォーマットの絞り込みを整理したが、その途中で目に付いたのが'meta_query'パラメータ。この'meta_query'パラメータは、カスタムフィールドの絞り込み条件を指定するためのもので、3.2で登場した新しいパラメータのようだ。
まずはカスタムフィールド関連パラメータのおさらいから。
これまでの query_posts関数でカスタムフィールドを使うケースとしては、特定のカスタムフィールドが設定されているものを絞り込む場合と、カスタムフィールドの値でソートする場合がある。例えば'ranking'が'1'の投稿を絞り込む場合は
query_posts( 'meta_key=ranking&meta_value=1' );
といった感じで記述できる。
また'ranking'で昇順にソートする場合なら
query_posts( 'meta_key=ranking&orderby=meta_key&order=asc' );
と指定できる。

'meta_query'を使ってみる

先ほどの'ranking'が'1'の投稿を絞り込みを'meta_query'パラメータで指定すると
query_posts(
	array(
		'meta_query' => array(
			array(	'key'=>'ranking',
				'value'=>'1'
				)
			)
		)
	);
といった感じになる。条件指定の'key'にはカスタムフィールドの名前として'ranking'を、'value'には'1'を指定することで、'ranking'の値が'1'の投稿を絞り込んでいる。この'meta_query'パラメータは、先週紹介した'tax_query'パラメータと同じような使い方ができるが、条件指定の連想配列の中身が若干違うので注意したい。

データ型と多彩な条件指定が可能

カスタムフィールドの値は基本的に文字列形式で保存されているが、それらは文字列としてではなく、数値、日時として使用することもあるだろう。'meta_query'パラメータでは、データ型を指定することで、数値や日時として条件指定できる。使用できるデータ型は次の通り。
データ型意味
'CHAR'文字
'NUMERIC''SIGNED'の別名
'DECIMAL'浮動小数点数
'SIGNED'整数(符号あり)
'UNSIGNED'整数(符号なし)
'DATE'日付
'DATETIME'日時
'TIME'時刻
'BINARY'バイナリー
また指定できる条件指定は次の通り。
データ型意味有効なデータ型
'='値と一致するすべて(省略時)
'!='値と一致しないすべて
'>'値より大きい数値系・日時系
'>='値以上数値系・日時系
'<'値より小さい数値系・日時系
'<='値以下数値系・日時系
'LIKE'値で指定した文字列に一致する'CHAR'
'NOT LIKE'値で指定した文字列に一致しない'CHAR'
'IN'値(配列)で指定した何れかに一致するすべて
'NOT IN'値(配列)で指定した何れにも一致しないすべて
'BETWEEN'2つの値で指定した範囲内(境界を含む)数値系・日時系
'NOT BETWEEN'2つの値で指定した範囲外数値系・日時系
これらの条件指定は、見てわかる通りSQLの条件指定に共通している。

基本的な使い方

それぞれの条件の使い方は、次の通りである。
・カスタムフィールド'addr1'の値が'東京都'の投稿
query_posts(
	array(
		'meta_query' => array(
			array(	'key'=>'addr1',
				'value'=>'東京都',
				'compare'=>'='
				)
			)
		)
	);
※この'='は、'compare'の指定を省略した時に適用される条件だが、きちんと記述した方がわかりやすいと思う。
・カスタムフィールド'addr1'の値が'東京都'以外の投稿
query_posts(
	array(
		'meta_query' => array(
			array(	'key'=>'addr1',
				'value'=>'東京都',
				'compare'=>'!='
				)
			)
		)
	);
・カスタムフィールド'price'の値が500より大きい投稿
query_posts(
	array(
		'meta_query' => array(
			array(	'key'=>'price',
				'value'=>'500',
				'compare'=>'>',
				'type'=>'NUMERIC'
				)
			)
		)
	);
※数値の条件は'type'の指定を忘れずに。
・カスタムフィールド'price'の値が500以上の投稿
query_posts(
	array(
		'meta_query' => array(
			array(	'key'=>'price',
				'value'=>'500',
				'compare'=>'>=',
				'type'=>'NUMERIC'
				)
			)
		)
	);
・カスタムフィールド'visited_at'の値が'2011/09/15'より前の投稿
query_posts(
	array(
		'meta_query' => array(
			array(	'key'=>'visited_at',
				'value'=>'2011/09/15',
				'compare'=>'<',
				'type'=>'DATE'
				)
			)
		)
	);
※日時の条件は'type'の指定を忘れずに。
・カスタムフィールド'visited_at'の値が'2011/09/15'以前の投稿
query_posts(
	array(
		'meta_query' => array(
			array(	'key'=>'visited_at',
				'value'=>'2011/09/15',
				'compare'=>'<=',
				'type'=>'DATE'
				)
			)
		)
	);
・カスタムフィールド'addr2'の値に'横浜市'が含まれている投稿
query_posts(
	array(
		'meta_query' => array(
			array(	'key'=>'addr2',
				'value'=>'横浜市',
				'compare'=>'LIKE'
				)
			)
		)
	);
※'LIKE'と次の'NOT LIKE'の'value'は、SQLのように'%'を付ける必要はない(query_posts(WP_Query)の実行時、値の前後に'%'が付与されるため)。なお'%'を含んだ文字を調べる場合は、そのまま値としてそのまま指定する(例:'value'=>'100%')。
・カスタムフィールド'addr2'の値に'横浜市'が含まれていない投稿
query_posts(
	array(
		'meta_query' => array(
			array(	'key'=>'addr2',
				'value'=>'横浜市',
				'compare'=>'NOT LIKE'
				)
			)
		)
	);
・カスタムフィールド'addr1'の値が'東京都'、'神奈川県'、'千葉県'の何れかの投稿
query_posts(
	array(
		'meta_query' => array(
			array(	'key'=>'addr1',
				'value'=>array( '東京都','神奈川県','千葉県' ),
				'compare'=>'IN'
				)
			)
		)
	);
・カスタムフィールド'addr1'の値が'東京都'、'神奈川県'、'千葉県'以外の投稿
query_posts(
	array(
		'meta_query' => array(
			array(	'key'=>'addr1',
				'value'=>array( '東京都','神奈川県','千葉県' ),
				'compare'=>'NOT IN'
				)
			)
		)
	);
・カスタムフィールド'wakeup_at'の値が'05:00:00'~'07:00:00'の範囲(境界を含む)の投稿
query_posts(
	array(
		'meta_query' => array(
			array(	'key'=>'wakeup__at',
				'value'=>array( '05:00:00', '07:00:00' ),
				'compare'=>'BETWEEN',
				'type'=>'TIME'
				)
			)
		)
	);
・カスタムフィールド'wakeup_at'の値が'05:00:00'より早いか'07:00:00'より遅い投稿
query_posts(
	array(
		'meta_query' => array(
			array(	'key'=>'wakeup__at',
				'value'=>array( '05:00:00', '07:00:00' ),
				'compare'=>'NOT BETWEEN',
				'type'=>'TIME'
				)
			)
		)
	);

複数の条件を組み合わせる

ここまでは単純な条件1つのみを指定した場合について紹介してきたが、これらの条件は複数を組み合わせることができる。
・カスタムフィールド'addr1'の値が'東京都'で、'price'の値が500以上の投稿
query_posts(
	array(
		'meta_query' => array(
			array(	'key'=>'addr1',
				'value'=>'東京都',
				'compare'=>'='
				),
			array(	'key'=>'price',
				'value'=>'500',
				'compare'=>'>=',
				'type'=>'NUMERIC'
				),
			'relation'=>'AND'
			)
		)
	);
'relation'には'AND'か'OR'を指定できる。省略した場合は'AND'になり、配列で指定したすべての条件を満たすのみがマッチする。
・カスタムフィールド'wakeup_at'の値が'01:00:00'~'03:00:00'の範囲か'05:00:00'~'07:00:00'の範囲の投稿
query_posts(
	array(
		'meta_query' => array(
			array(	'key'=>'wakeup__at',
				'value'=>array( '01:00:00', '03:00:00' ),
				'compare'=>'BETWEEN',
				'type'=>'TIME'
				),
			array(	'key'=>'wakeup__at',
				'value'=>array( '05:00:00', '07:00:00' ),
				'compare'=>'BETWEEN',
				'type'=>'TIME'
				),
			'relation'=>'OR'
			)
		)
	);

いくつか注意点

'meta_query'パラメータは、SQLの知識があれば使いこなしは容易だろう。使いこなす上でポイントの1つは、大小や範囲指定の条件では必ず数値系や日時系のデータ型を指定すること。データ型の指定を忘れると、意図した検索結果を得ることができない。
あとは便利だからといって、複雑な条件の組み合わせることはできるだけ避けた方がいい。特に'LIKE'条件との組み合わせはデータベースの検索処理を複雑にしてしまい、結果的に検索時間が長くなってしまう可能性が高い。
最後に'meta_query'パラメータ使用時の'orderby'パラメータで'meta_key'を指定した場合の振る舞いについて少しだけ。このページの冒頭付近で触れたように'orderby'パラメータで'meta_key'を指定し、'meta_key'パラメータでカスタムフィールドの名前を指定することで、そのカスタムフィールドの値に従って検索結果をソートできるのだが、'meta_query'パラメータで指定した条件によっては意図した並び順にならないケースがあった。将来的に改善されるとは思うが、カスタムフィールドによるソートは注意が必要だろう。

最終更新 : 2011年09月15日 13:10


お勧め

delete_post_meta(2018年5月27日 更新)

bool delete_post_meta( int $post_id, string $meta_key [ , mixed $meta_value = '' ] )
投稿情報のカスタムフィールド情報を削除する。

wp_is_numeric_array(2018年5月27日 更新)

bool wp_is_numeric_array( mixed $data )
数値キーのみの配列か調べる。

get_tag_regex(2013年8月3日 更新)

string get_tag_regex( string $tag )
HTMLタグの正規表現パターンを取得する。

get_all_page_ids(2012年5月30日 更新)

array get_all_page_ids( )
全ページ(post_typeが'page')の投稿IDを取得する。

the_post_thumbnail_caption(2018年5月27日 更新)

void the_post_thumbnail_caption( mixed $post = null )
投稿ページのサムネイル(アイキャッチ画像)キャプションを表示する。