更新:2018年06月20日/ろあんぬ(WEB)

WordPressのサイト内検索でカスタムフィールドの内容も検索結果に含める方法

こんにちは、ろあんぬ です。

今回は、Wordpressで使用する「サイト内検索」で「カスタムフィールド」の内容も検索させるやり方について紹介します。

恐らくこの記事に辿りついた方は、相当苦労したのではないかと察します。

私がまさにそうでしたからね。

この問題は何年も前から制作者の悩みの種となっており、Wordpressでブログ以外のサイトを運用した(制作した)人であれば一度はぶつかる壁じゃないでしょうか。

で、こんだけ悩む人が多いんですから、当然ググれば山のように解決策を書いてるページがHITするわけです。わたしもかなり多数のサイトを参考にさせて頂きました。

しかし残念なことに、実際にエラーが起こらず使えた方法がほとんどありませんでした…。
私のやりたいことがちょっと特種な条件を持ってたせいもあるんですけどね。
ただ、同じ悩みを抱えている方の参考になるかもしれないので、私が試したものと、最終的に落ち着いた導入方法を記しておこうと思います。

WPプラグイン「Search Everything」を導入してみた

まず真っ先に思いつく方法がコレですよね。たぶんw
検索してもこれの使い方を解説しているページがゴロゴロあります。私もそうだったので、まずは入れてみました。これでうまく行けば簡単に済むし。

Search Everything

結果

WPのバージョンのせいなのか?私はWP最新版「4.9.6」で試しましたが、検索ワードが空の時の処理でエラーを吐いてしまって、「これはダメだ…」となりました。無念。WPの仕様で、検索ワードが空の場合に検索ボタンが押された時の仕様が途中から変わった経緯があるので、そのせいかもしれません。

カスタムフィールドが無限に増えてもプラグインなしで検索対象にする

こちらのブログで紹介されている方法です。とても魅力的な見出しで、これは良さそうだ!とクリックしました。実装方法については先方のブログを参照してください。私も書かれている通りに実装させて頂きました。

結果

場合によってはうまく動く。最初は私も問題なく動いていたんです。途中からお客様の要望で、サイドバーにある関連記事の取得方法で「meta_key」を使用してから気付いた。これ、他のループが検索ページにあって、meta_keyをクエリに含めるとエラー出てしまうヤツ……。
というわけで、他に特種なループ処理をしないのであれば上記ページのやり方で動きます。私はダメだった。無念。

functions.phpじゃなくて直接search.phpのクエリ取得方法を変える

次に試したのが、こちらのブログで紹介されているやり方です。主さんいわく、ベトナムのエンジニアさんが紹介していたやり方とのこと。

ブログのコメント欄でも書かれていましたが、既出の問題として、こちらのソースで実行すると、検索ワードが該当0件だった場合、記事取得の際の配列が空っぽになるため、記事内ソースコードの19行目にある「$post_ids」が空の場合、「array(0)」をセットしてやる必要があります。これの処理を自分で加えないと、検索結果が0HITだった場合に「全件表示される」という悲惨な結末になってしまいました。

さらにいうと、7行目に書かれている「like_escape()」がすでに非推奨の関数になってしまっているため、これを「esc_like()」とかに変更する必要がありました。

上記2か所を改修し、meta_keyとのバッティングも無くなり、今度こそこれでいけるー!と喜んだのですが。

結果

検索ワードに「’(シングルクォーテーション)」が含まれていると検索結果0件になってしまった。WPのオリジナルの検索結果画面では正しくシングルクォーテーションが取得できているので、DBの情報をゴニョゴニョした時にエスケープ処理がうまく出来てないとか、そんな問題が潜んでいるんだと思います。正直わたしはそこまでプログラムに詳しくないため、どうしたらそれが解消できるかわからなかったです…。というわけで他をあたりました…。無念。

私の辿りついたコードはコレ

こちらのブログで紹介されている方法で、私はうまく実装することができました。ただこちらも「$wpdb->escape(“%{$word}%”);」の部分でエラーが出てしまうので、「’%’ . esc_sql( $word ) . ‘%’;」へ置き換えしました。あと、私はカスタムフィールドのみを検索対象として追加したかったので、タクソノミーやらユーザー名やらは検索対象から外させてもらいました。

最終的に実装したコードは下記です。

function custom_search($search, $wp_query) {
	global $wpdb;

	if (!$wp_query->is_search)
			return $search;
	if (!isset($wp_query->query_vars))
			return $search;

	$search_words = explode(' ', isset($wp_query->query_vars['s']) ? $wp_query->query_vars['s'] : '');
	if ( count($search_words) > 0 ) {
			$search = '';
			$search .= "AND post_type = 'post'";
			foreach ( $search_words as $word ) {
					if ( !empty($word) ) {
							$search_word = '%' . esc_sql( $word ) . '%';
							$search .= " AND (
								 {$wpdb->posts}.post_title LIKE '{$search_word}'
								OR {$wpdb->posts}.post_content LIKE '{$search_word}'
								OR {$wpdb->posts}.ID IN (
								SELECT distinct post_id
								FROM {$wpdb->postmeta}
								WHERE meta_value LIKE '{$search_word}'
								)
							) ";
						
					}
			}
	}
	return $search;
}
add_filter('posts_search','custom_search', 10, 2);

これをfunctions.phpに貼りつけ、あとは普通にsearch.phpを作るだけでOK!カテゴリ名やユーザー名なども検索対象にしたい人は、元のブログ様からソースを貰ってください。最初の方に書きましたが、「$wpdb->escape(“%{$word}%”);」の部分を「’%’ . esc_sql( $word ) . ‘%’;」に直せばエラーも消えて、動作すると思います。

meta_key使っても競合しないし、キーワード一致が無かった時は0件になってくれるし、検索ワードにシングルクォーテーションがあっても検索出来たし、今のところ問題点がすべて解消されています。

どの記事を参考にしたら良いか悩んでいる方の参考になれば幸いです。

この記事を書いた人

ろあんぬ

サイトの制作担当。主にアビスリウム・WEB制作関連の記事を書いています。最近はラグナロクマスターズにハマっています。ほぼブログの更新つぶやきになってるけど一応Twitterもやってます。話しかけてもらえたら反応します!(@roanne_mohulog)

スポンサーリンク

関連記事

Comments コメントを書く

  1. toorimon より:

    色々探し回り、この記事のおかげでようやく希望の実装することができました、感謝です!

  2. kana より:

    こんにちは、是非ソースを利用したいのですが、元サイトのブログが削除されているようで、確認ができません。
    申し訳ありませんが、元のソースをご教示いただくことは可能でしょうか。

    • ろあんぬ より:

      >kana様
      コメントありがとうございます!元ブログが消えてしまっているというのも、こちらのコメントを見て気づきました…。消えてますね…。
      残念ながら大元のソースは所持しておらずご提示が出来ないのですが、こちらの記事のソースなどでうまく行かないか試してみてください。ソースもほぼ一緒なので、派生元が一緒なんだと思います。いくつか似たようなソースを掲載しているサイトがヒットしましたので、ソースの一部を使ってGoogle検索してみて、希望の動作をするソースを探してみるのも良いかもしれません!

  3. […] 参考サイト:WordPressのサイト内検索でカスタムフィールドの内容も検索結果に含める方法 […]

  4. […] WordPressのサイト内検索でカスタムフィールドの内容も検索結果に含める方法 https://mohulog.com/20180620_1732/ […]

コメントを書く

入力エリアすべてが必須項目です。メールアドレスが公開されることはありません。

内容をご確認の上、送信してください。

PageTop