WordPress検索でカスタムフィールドも対象にする方法(functions.php)

PCで検索

WordPressをある程度使い込んでいる方ならご存じだと思いますが、標準のサイト内検索はカスタムフィールドの値を検索対象に含めません

投稿タイトルや本文は検索対象になりますが、カスタムフィールド(postmetaテーブルに保存されるデータ)は検索対象外です。そのため、例えば次のようなケースでは検索が機能しません。

  • 店舗情報サイトで住所や電話番号をカスタムフィールドに保存している
  • 商品データの型番やSKUをカスタムフィールドで管理している
  • ACFなどで拡張した情報を検索対象にしたい

特にデータ量が多いサイトほど、この仕様はかなり不便です。実際、私が運用しているサイトでも記事数が10万件近くあり、検索精度を上げるためにカスタムフィールド検索は必須でした。

そこで、

  • プラグインで解決する方法
  • functions.phpで直接対応する方法

この2つを実際に試しました。結果的に、最も安定して運用できた方法も含めて紹介します。

WPプラグイン「Search Everything」

まず最初に試したのが、有名な検索拡張プラグインSearch Everythingです。
古くから紹介されている定番プラグインで、カスタムフィールド検索にも対応しています。

プラグインで解決できるなら、それに越したことはありません。
管理画面から有効化するだけなので、導入も非常に簡単です。

  • カスタムフィールドを検索対象に追加できる
  • カテゴリやタグの検索も拡張可能
  • 設定が比較的シンプル

ただし、私の環境では検索処理がかなり重くなりました

記事数が多いサイトでは、検索クエリが大きくなりやすく、ページ表示が明らかに遅くなります。10万件規模の投稿+大量のカスタムフィールドがある環境では、正直実用レベルではありませんでした。

もちろん、小規模サイトであれば問題なく使える可能性があります。まずは試してみる価値はあると思います。

LINK Search Everything

WPプラグイン「Custom Fields Search by BestWebSoft」

次に試したのがCustom Fields Search by BestWebSoftというプラグインです。

このプラグインの特徴は、検索対象にするカスタムフィールドを細かく指定できる点です。つまり、必要なフィールドだけを検索対象にできます。

  • 検索対象のカスタムフィールドを指定できる
  • 不要なメタデータを除外できる
  • 比較的軽量な検索処理

実際、導入当初は非常にうまく動作していました。

しかし、ある時期を境に突然動作しなくなりました。正確な原因は特定できていませんが、次のような可能性は考えられます。

  • PHPバージョンの変更
  • WordPress本体のアップデート
  • プラグインの更新停止

現在はWordPress公式ディレクトリで配布されていないようなので、残念ながら使用を断念しました。プラグインは便利ですが、更新停止や互換性問題が発生するリスクは避けられません。

その結果、最終的に辿り着いたのが次の方法です。

functions.phpでカスタムフィールドを検索対象にする

最終的に採用したのはfunctions.phpに検索処理を追加する方法です。

WordPressの検索は内部的にSQLクエリを生成しています。そこで、その検索条件にpostmetaテーブルのmeta_valueを追加すれば、カスタムフィールドも検索対象にできます。

実際のコードはこちらです。

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に追加するだけで、カスタムフィールドの値も検索対象になります。

プラグインと違って余計な処理が入らないため、パフォーマンスも比較的安定しています。

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

特定のカスタムフィールドだけ検索対象にする方法

サイトによっては、すべてのカスタムフィールドを検索対象にするとノイズが増える場合があります。

例えば次のようなデータです。

  • 郵便番号
  • 内部管理用のID
  • アクセス情報

こうしたフィールドまで検索対象にすると、検索結果が意図しない形になることがあります。

その場合は、検索対象のフィールドを制御する方法が有効です。次のコードは、特定のカスタムフィールドを検索対象から除外する例です。

function cf_search_join($join) {
    global $wpdb;
    if (is_search()) {
        $join. = ' LEFT JOIN '.$wpdb - > postmeta.
        ' ON '.$wpdb - > posts.
        '.ID = '.$wpdb - > postmeta.
        '.post_id ';
    }
    return $join;
}
add_filter('posts_join', 'cf_search_join');

function cf_search_where($where) {
    global $wpdb;
    if (is_search()) {
        $where = preg_replace("/\(\s*".$wpdb - > posts.
            ".post_title\s+LIKE\s*(\'[^\']+\')\s*\)/", "(".$wpdb - > posts.
            ".post_title LIKE $1) OR (".$wpdb - > postmeta.
            ".meta_value LIKE $1)", $where);
        $where. = " AND (".$wpdb - > postmeta.
        ".meta_key NOT LIKE 'number')";
        $where. = " AND (".$wpdb - > postmeta.
        ".meta_key NOT LIKE 'zip')";
        $where. = " AND (".$wpdb - > postmeta.
        ".meta_key NOT LIKE 'access')";
    }
    return $where;
}
add_filter('posts_where', 'cf_search_where');

function cf_search_distinct($where) {
    global $wpdb;
    if (is_search()) {
        return "DISTINCT";
    }
    return $where;
}
add_filter('posts_distinct', 'cf_search_distinct');

この方法を使えば、検索対象を細かくコントロールできます。

WordPress検索を拡張するならコード対応が最も安定

WordPressの検索機能は非常にシンプルですが、そのぶん拡張性は高い仕組みになっています。

今回試した結果をまとめると次の通りです。

  • プラグインは手軽だが重くなる場合がある
  • 更新停止のリスクがある
  • 大規模サイトではパフォーマンス問題が出やすい

一方、functions.phpで対応する方法は次のメリットがあります。

  • 処理内容を完全にコントロールできる
  • 余計な処理が入らない
  • 大規模サイトでも比較的安定する

WordPressはカスタムフィールドの活用が前提になっているCMSです。それにも関わらず、標準検索がカスタムフィールドを対象にしていないのは、正直なところ少し不便に感じます。

とはいえ、今回紹介した方法を使えば問題なく対応できます。

検索機能の精度はサイトの使いやすさに直結します。カスタムフィールドを多用しているサイトなら、ぜひ一度見直してみてください。