WordPressでカスタムフィールドとカスタムタクソノミーを検索対象に含めたら検索結果ページ振り分けが動作しなくなった件

とある案件で、複合技を使用したところ問題発生したので備忘録です。

  1. 3つの要件
  2. 要件1 検索対象にカスタムフィールドとカスタムタクソノミーを含める
  3. 要件2 サイト内全検索フォームと絞り込み検索(特定カスタム投稿 custom のみ)フォームを分ける
  4. 要件3 検索結果ページを分ける
  5. まとめ

3つの要件

  1. 検索対象にカスタムフィールドとカスタムタクソノミーを含める
  2. サイト内全検索フォームと絞り込み検索(特定カスタム投稿 custom のみ)フォームを分ける
  3. 索結果ページを分ける

要件1 検索対象にカスタムフィールドとカスタムタクソノミーを含める

WordPressの標準搭載されている検索機能では、カスタムフィールドの値やタクソノミーの値は検索対象となっていません。
そこで、検索対象にカスタムフィールドやタクソノミーを含める方法を探りました。

検索対象にカスタムフィールドを含める

function.phpに記述します。

function posts_search_custom_fields( $orig_search, $query) {
	if($query->is_search() && $query->is_main_query() && ! is_admin()) {
		global $wpdb;
		$q = $query->query_vars;
		$n = ! empty( $q['exact'] ) ? '' : '%';
		$searchand = $query_temp = '';
		$query_temp = $q['search_terms'];

		if( $query_temp ) {
			foreach($query_temp as $term) {
				$include = '-' !== substr( $term, 0, 1 );
				if($include) {
					$like_op  = 'LIKE';
					$andor_op = 'OR';
				} else {
					$like_op  = 'NOT LIKE';
					$andor_op = 'AND';
					$term     = substr( $term, 1 );
				}
				$like = $n . $wpdb->esc_like($term) . $n;
				
				$search .= $wpdb->prepare("{$searchand}(($wpdb->posts.post_title $like_op %s) $andor_op ($wpdb->posts.post_content $like_op %s) $andor_op (custom.meta_value $like_op %s))", $like, $like, $like);
				$searchand = ' AND ';
			}
		} // end if

		if(!empty($search)) {
			$search = " AND ({$search}) ";
			if(!is_user_logged_in())
				$search .= " AND ($wpdb->posts.post_password = '') ";
		}
		return $search;
	}
	else {
		return $orig_search;
	}
}

function posts_join_custom_fields($join, $query) {
	if($query->is_search() && $query->is_main_query() && ! is_admin()) {
		global $wpdb;
		$join .= " INNER JOIN ( ";
		$join .= " SELECT post_id, group_concat( meta_value separator ' ') AS meta_value FROM $wpdb->postmeta ";
		$join .= " GROUP BY post_id ";
		$join .= " ) AS custom ON ($wpdb->posts.ID = custom.post_id) ";
	}
	return $join;
}
add_filter('posts_search', 'posts_search_custom_fields', 10, 2);
add_filter('posts_join', 'posts_join_custom_fields', 10, 2);

参考元:カスタムフィールドを検索対象に含める

検索対象にタクソノミーを含める

function.phpに記述します。

function atom_search_where($where){
	global $wpdb;
	if(is_search())
		// COLLATE utf8_unicode_ciで「ひらがな」と「カタカナ」、「全角英数」と「半角英数」を区別しないでマッチさせる
		$where .= "OR (t.name COLLATE utf8_unicode_ci LIKE '%".get_search_query()."%' AND {$wpdb->posts}.post_status = 'publish')";
	return $where;
}

function atom_search_join($join){
	global $wpdb;
	if(is_search())
		$join .= "LEFT JOIN {$wpdb->term_relationships} tr ON {$wpdb->posts}.ID = tr.object_id INNER JOIN {$wpdb->term_taxonomy} tt ON tt.term_taxonomy_id=tr.term_taxonomy_id INNER JOIN {$wpdb->terms} t ON t.term_id = tt.term_id";
	return $join;
}

function atom_search_groupby($groupby){
	global $wpdb;

	$groupby_id = "{$wpdb->posts}.ID";
	if(!is_search() || strpos($groupby, $groupby_id) !== false) return $groupby;

	if(!strlen(trim($groupby))) return $groupby_id;

	return $groupby.", ".$groupby_id;
}

add_filter('posts_where','atom_search_where');
add_filter('posts_join', 'atom_search_join');
add_filter('posts_groupby', 'atom_search_groupby');

参考元:WordPressでカテゴリー、タグ、カスタムタクソノミーを検索対象に含める方法

検索対象にカスタムフィールドを含める方法やタクソノミーを含める方法など、それぞれ個別に含める方法は見つかりました。しかし、それらを合体させる事ができませんでした。
仕方ないのでプラグインを使用することにしました。

プラグイン「WP Extended Search」

WP Extended Search は WordPress に標準搭載されている検索機能を拡張し、カスタマイズできるプラグインです。
インストール後有効化しますと、ダッシュボードの「設定」メニューの中に追加されます。

WP Extended Search

検索対象

  • タイトル
  • 投稿内容
  • 抜粋
  • カスタムフィールド
  • カテゴリー
  • タグ
  • カスタムタクソノミー
  • 投稿者表示名
  • 投稿タイプ

設定

  • General Search Setting
    検索対象に含める項目(上からタイトル・コンテンツ・抜粋)を選択
  • Select Meta Key Names
    検索対象に含めるカスタムフィールドの値を選択
  • Select Taxonomies
    検索対象に含めるタクソノミーを選択
  • Author Setting
    検索対象に投稿者の表示名を含めるかどうかを選択
  • Select Post Types
    検索対象に含める投稿タイプを選択
  • Terms Relation Type
    入力された検索キーワードが複数個ある場合、AND検索/OR検索を設定可能
  • Select date to exclude older results
    古い記事を検索対象から除外したい場合に日付を設定可能
  • Posts per page
    検索結果ページに表示する投稿数を指定可能

これで要件1クリア。カスタムフィールドとカスタムタクソノミーを検索対象に含める事ができました。

要件2 サイト内全検索フォームと絞り込み検索(特定カスタム投稿 custom のみ)フォームを分ける

サイト内全検索フォーム

<form action="<?php echo home_url(); ?>" method="get">
<input type="search" name="s" value="<?php echo get_search_query(); ?>">
<input type="submit" name="search" value="検索">
</form>

絞り込み検索フォーム

<form action="<?php echo home_url(); ?>" method="get">
<input type="search" name="s" value="<?php the_search_query(); ?>">
<input type="hidden" name="post_type" value="custom">
<input type="submit" name="search" value="検索">
</form>

通常のサイト内全検索フォームと絞り込み検索フォームの違いは3行目
hidden タイプの input を追加し、value の値に custom(カスタム投稿のスラッグ)を指定することです。

これで要件2クリア。検索フォームを分けることができました。

要件3 検索結果ページを分ける

サイト内全検索結果ページと絞り込み検索結果ページでデザインを変える必要があったため、検索結果ページを分けることにしました。

検索結果ページ振り分け

function.phpに記述します。

function custom_search_template($template){
	if(is_search()) {
		$post_types = get_query_var('post_type');
		foreach ((array) $post_types as $post_type)
			$templates[] = "search-{$post_type}.php";
		$templates[] = 'search.php';
		$template = get_query_template('search',$templates);
	}
	return $template;
}
add_filter('template_include','custom_search_template');

サイト内全検索結果ページはsearch.phpで、絞り込み検索結果ページはsearch-custom.phpで表示されるようになります。

検索結果ページが振り分けられない問題発生

しかし、検索結果ページ振り分けが機能がうまく動きません。
サイト内全検索でも絞り込み検索結果ページで表示されます。

試行錯誤の末、プラグイン「WP Extended Search」が原因であると分かりました。
しかし、要件1クリアのためにこのプラグインは必須。

調査したところ、サイト内全検索フォームからの検索でも $post_types にカスタム投稿のスラッグが入ってしまうことが原因のようでした。
おそらく、WP Extended Search の Select Post Types 設定でカスタム投稿を検索対象に含めたからだと考えられます。

問題解決のために

$post_types に入るスラッグでの検索結果ページ判別は使えません。
そこで検索結果の URL に着目しました。

  • サイト内全検索フォームから検索した時のURL
    サイトurl/?s=検索ワード&search=検索
  • 絞り込み検索フォームから検索した時のURL
    サイトurl/?s=検索ワード&post_type=custom&search=検索

絞り込み検索フォームから検索した時の URL の場合、post_type=custom というワードが入ります。
これを使って検索結果ページ振り分けを修正したいと思います。

検索結果ページ振り分けを修正

function.phpに記述します。

function custom_search_template($template){
	if(is_search()) {
		$url = esc_url($_SERVER['REQUEST_URI']);
		if(strpos($url, 'post_type=custom') !== false) {
			$templates[] = "search-custom.php";
		} else {
			$templates[] = 'search.php';
		}
		$template = get_query_template('search',$templates);
	}
	return $template;
}
add_filter('template_include','custom_search_template');
  • 3行目 URLを取得
  • 4行目 文字列の中に「post_type=custom」が含まれていたら
  • 5行目 search-custom.php を代入
  • 6行目 文字列の中に「post_type=custom」が含まれていなかったら
  • 7行目 search.php を代入

これで要件3クリア。
全ての要件をクリアできました。

まとめ

プラグイン「WP Extended Search」の設定で検索対象にカスタム投稿を含める場合、検索結果ページ振り分けがうまく動かないと考えられるので、URLを使って判別すると良いでしょう。

書いた人:やまライダー(嫁)

Web屋さんで8時間フルタイム勤務をしている、いわゆるワーキングマザー。
夫婦共働きで、ムスメ氏を育てています。
主に資産運用にかかわるお金の話、ムスメ氏を育てていく上での子育ての話、そしてたまにお仕事関連の記事を書いていく予定。
プロフィールを見る