WordPress では記事検索は標準機能として持っていて、検索フォームの設置はとても簡単にできます。

ただこの検索機能、検索対象は記事の「タイトル」と「投稿」の内容だけになっています。ということは Advanced Custom Fields とかを使ってページのコンテンツを作るようにした場合、それらの内容はまるっきり無視されてしまうことになります。

いま携わっている案件ではいろんなデザインパーツを ACF で作ったカスタムフィールドにテキストや数値を入力するだけで作れるようにしていて、投稿部分にはまるっきりコンテンツが入っていない状態なのでこのままでは検索に何も引っかからないという事態に…。

しかし WordPress である程度の規模の Web サイトを作ろうと思うとカスタムフィールドを使わないわけにもいかないだろうし、何かスマートな方法が有るだろう!と思って調べてみたら意外と無いんですね。プラグインも有ったことは有ったのですが、カスタムフィールドの数百とものすごい数なので動作がとんでもなく遅くなり使い物になりませんでした。

なので例によって function.php にコードを書くことで解決。

プラグインを使わない方法としては2種類あって、一つはサブループで検索処理を行うもので function.php ではなく search.php にコードを書く方法。

Welcart カスタマイズ ブログ 「プラグインなしでカスタムフィールドの値を検索範囲に反映させる方法

こちらはフィルターフックを使わないのでなんとなく安全なイメージがありましたが、ページ送りがうまく出来ず断念。なので最終的にはメインプールで検索処理を行うために function.php にフィルターフックを追加しました。

/**
 * Extend WordPress search to include custom fields
 * http://adambalee.com
 */
/**
 * Join posts and postmeta tables
 * http://codex.wordpress.org/Plugin_API/Filter_Reference/posts_join
 */
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');

/**
 * Modify the search query with posts_where
 * http://codex.wordpress.org/Plugin_API/Filter_Reference/posts_where
 */
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);
    }
    return $where;
}
add_filter('posts_where', 'cf_search_where');

/**
 * Prevent duplicates
 * http://codex.wordpress.org/Plugin_API/Filter_Reference/posts_distinct
 */
function cf_search_distinct($where) {
    global $wpdb;
    if (is_search()) {
        return "DISTINCT";
    }
    return $where;
}
add_filter('posts_distinct', 'cf_search_distinct');

コードは鼻ちょうちんさんの「カスタムフィールドが無限に増えてもプラグインなしで検索対象にする」の内容を引用させていただきました。

自分の場合は更に結果の順序や1ページあたりの結果表示数を設定したかったので次のコードも追加しました。

function set_search_target($query) {
  if ( is_admin() || ! $query->is_main_query() ) {
    return;
  }
  if ( is_search() ) { //検索結果
    $query->set( 'orderby', 'date' );
    $query->set( 'order', 'DESC' );
    $query->set( 'posts_per_page', 10 );
    return;
  }
}

add_action( 'pre_get_posts', 'set_search_target' );

メインループで処理を行うとページ送りも特に気にせず利用できるので、処理はできるだけメインループで行うようにした方が良いですね。

しかしカスタムフィールドを検索対象に含めるのが標準機能として持っていないとは思いませんでした。Gutenberg も大事かもしれませんが、予約更新やリビジョン管理、そしてこのカスタムフィールドを検索対象に含めたりと CMS としてもっと先にやるべきことが有りそうなんですけどねえ。


0件のコメント

コメントを残す

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

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください