WordPressでカスタムフィールドの部分一致検索ができた

今回のエントリー作成にあたっては、WordPressの日本語フォーラムで活発なフォローをされている@kzxtremeさんのエントリー

WordPress のURLクエリストリングにカスタムフィールドを指定して絞り込み検索する
http://wpxtreme.jp/search-with-custom-fields-in-url-query-parameters

がたいへん参考になりました。まずは@kzxtremeさんに大感謝です  😀

私は何をしたかったのか

カスタム投稿の記事を、カスタムフィールドの値で絞り込み検索したかったのです。具体的にいうと、会議室・レンタルスペースのガイド的なサイトを

  • 会議室・レンタルスペースの個別ページ……カスタム投稿「facilities」で登録
  • 駐車場の有無……カスタムフィールドで定義。キーは「parking」、値は「あり(無料)」「あり(有料)」「なし」の3とおり

というかたちで作っていて、「facilities」の全投稿の中から駐車場がある施設、つまり、値に「あり(無料)」「あり(有料)」のいずれかを持つものを抽出したかったんですね。

最初にやったこと

@kzxtremeさんのエントリーにあるサンプルコード(「よりクールな方法」の方)をもとに functions.php に

global $my_public_query_vars;
$my_public_query_vars = array( 'parking' );

add_filter( 'query_vars', 'my_query_vars' );
function my_query_vars( $public_query_vars ) {
	global $my_public_query_vars;
	return array_merge( $public_query_vars, $my_public_query_vars );
}

add_action( 'pre_get_posts', 'my_pre_get_posts' );
function my_pre_get_posts( $query ) {
	if ( ! is_admin() && is_post_type_archive( 'facilities' ) /* && 'staff' == $query->get( 'post_type' ) */ ) {
		$meta_query = array();

		global $my_public_query_vars;
		foreach ( $my_public_query_vars as $key ) {
			if ( $val = $query->get( $key ) ) {
			$meta_query[] = array(
				'key'   => $key,
				'value' => $val,
				);
			}
		}

		if ( ! empty( $meta_query ) ) {
			$query->set( 'meta_query', $meta_query );
		}
	}
}

と書きました。ざっくり簡単に補足すると

  • 前半……URLクエリストリングに「parking」を使えるように設定
  • 後半……「facilities」のアーカイブページが表示されているとき、カスタムフィールド「parking」の値を抽出、値に応じてループのクエリを書き換える

という流れになってます。

検索フォームと結果表示のページをどう作る?

そですね。作らないといけません。

検索フォームはこんなかたちで書きました。

<form method="get" id="searchform-parking" action="<?php echo esc_url( home_url( '/facilities/' ) ); ?>">
	<input type="checkbox" class="field" id="parking" name="parking" value="あり"/>駐車場あり<br />
	<input type="submit" class="submit" name="submit" id="searchsubmit-parking" value="検索" />
</form>

1行目の home_url( ‘/facilities/’ ) が functions.php の内容と関係する記述です。こう書くことで http://www.example.com/facilities/?parking=あり というURLになったとき、駐車場がある施設が抽出されることになるわけです。

もっとも、これだと archive.php が検索結果の表示に使われるので、デザインのカスタマイズをしたい場合はテンプレート階層を活用して archive-facilities.php を新規作成のうえごにょごにょする必要があります。

ところがこれだと該当数ゼロになる

ええ、ゼロになってしまいました。

カスタムフィールドの値は「あり(無料)」「あり(有料)」「なし」の3とおり。ところが、検索フォームでは「あり」という値で呼び出しをかけています。カスタムフィールドにない値で斜め上行く検索をして、該当数ゼロになってる……つまり、この方法は「完全一致検索」を狙わないと使えないやりかただったのです。

魔法の呪文 ‘compare’ => ‘LIKE’

そんな状況を先読みしてたかどうかはわかりませんが、WordPressの中の方たちはすごいですね。部分一致検索ができる呪文を用意してくれてました。それが ‘compare’ => ‘LIKE’ というフレーズです。

Codexの英語版にこんな解説があります。@bren_bossさんありがとう。

  • meta_query (array) – Custom field parameters (available with Version 3.1).
    • key (string) – Custom field key.
    • value (string|array) – Custom field value (Note: Array support is limited to a compare value of ‘IN’, ‘NOT IN’, ‘BETWEEN’, or ‘NOT BETWEEN’)
    • compare (string) – Operator to test. Possible values are ‘=’, ‘!=’, ‘>’, ‘>=’, ‘<‘, ‘<=’, ‘LIKE’, ‘NOT LIKE’, ‘IN’, ‘NOT IN’, ‘BETWEEN’, ‘NOT BETWEEN’. Default value is ‘=’.
    • type (string) – Custom field type. Possible values are ‘NUMERIC’, ‘BINARY’, ‘CHAR’, ‘DATE’, ‘DATETIME’, ‘DECIMAL’, ‘SIGNED’, ‘TIME’, ‘UNSIGNED’. Default value is ‘CHAR’.

「compare」の欄に注目ですね。デフォルトだと = (完全一致)でカスタムフィールドの値を検索するところ、SQLのLIKE演算子よろしく部分一致の設定ができるのです。部分一致を実現するには先ほどの functions.php にて

- 'value' => $val,
+ 'value' => $val,
+ 'compare' => 'LIKE'

と書けばオッケイ。これでやっと、「あり(無料)」「あり(有料)」両方の記事を引っぱってくることができるようになりました。

ほかにもSQLにならった演算子があったり、データ型を指定できたりもするので、興味がある方はいろいろ試されてはいかがでしょうか。

「WordPressでカスタムフィールドの部分一致検索ができた」への5件のフィードバック

  1. カスタム投稿タイプとカスタムフィールドの検索、大変参考になり、絞り込み検索ができそうです。
    これは、search.phpが使われ、検索件数も出るのでしょうか。

    1. berghiloさん

      こんな辺境ブログにお越しくださり、ありがとうございます 🙂
      上記のコード例ですと、検索フォームの action 属性を

      <?php echo esc_url( home_url( '/facilities/' ) ); ?>
      

      としているので、検索結果には archive-facilities.php というテンプレートファイルが使われることになります。どうして search.php の代わりに archive-facilities.php を使うようにしたのか、すいません記憶があいまいで覚えてなくて……

      検索件数を表示したいということでしたら、テンプレートファイル内に

      <p><?php echo $wp_query -> post_count; ?></p>
      

      と書けば表示されるかと思います(一応検証しましたが、実際に試してご確認ください)。

  2. teckingさん、早速のご返答ありがとうございます。
    試したところ、ばっちりできて、小躍りしていたんですが、ページが次ページにまたがると総数が表示できないみたいでした。
    ええと、つまり検索結果が2ページになると今見ている1ページ分の件数しか出ませんでした。
    難しいですね。

  3. こんにちは。
    wordpress4.1.1を使用しているのですが
    チェックボックスが複数の場合、’compare’ => ‘LIKE’では正常に検索できないようです。
    駐車場あり1
    駐車場あり2
    こんな感じの場合です。
    エラーコードはNotice: Array to string conversion in

    ‘compare’ => ‘IN’にすると複数のチェックボックスでも検索できできます。

    只、通常のキーワード検索時にカスタムフィールドの検索ができないようです。
    何か方法はあるのでしょうか?

    1. こよーてさん

      functions.php のサンプルコード2行目

      $my_public_query_vars = array( 'parking' );

      の array() にカスタムフィールドのキー(meta_key)を列記してみてはどうでしょう?

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です