プラグインを使用せずに、フリーワード、カテゴリー、タグで絞り込み検索を実装する方法を紹介します。
絞り込み検索は”WP_Query”のパラメーター、”tax_query”を活用するのがポイントです 。

【前準備】タクソノミー(カテゴリー)名を検索できるようにしておく
WordPress5からタクソノミーも検索対象になっているような気がするようなしないような… 現在調査中です。(2019年11月3日現在)
また追記します。(スミマセン)
WordPressデフォルトではカテゴリー名はフリーワードで検索できず…事前準備として対策しておきます。 手っ取り早くプラグインを使用する方法と、functions.phpに記述する方法、両方書いておきますね。
方法1 プラグインを使用する
“WP Extended Search”プラグインを使用します。
方法2 function.phpに記述する
SQL文を使用してカテゴリー名を検索しています。
function my_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 = ''; 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 tr.object_id FROM {$wpdb->term_relationships} AS tr INNER JOIN {$wpdb->term_taxonomy} AS tt ON tr.term_taxonomy_id = tt.term_taxonomy_id INNER JOIN {$wpdb->terms} AS t ON tt.term_id = t.term_id WHERE t.name LIKE '{$search_word}' OR t.slug LIKE '{$search_word}' OR tt.description 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','my_custom_search', 10, 2);
とりあえずコード全部
「searchform.php」が検索フォーム、「search.php」が検索結果を表示するテンプレートになります。「search.php」の下部でget_search_form() 関数で「searchform.php」を読み込んでおり、結果ページでも検索フォームを表示して再検索できるようにしています。
searchform.php
<form role="search" method="get" id="searchform" action="<?php echo esc_url(home_url('/')); ?>"> <h2>カテゴリー</h2> <?php $category_args = array( 'orderby' => 'name', 'order' => 'ASC', ); $categories = get_terms( 'category', $category_args ); foreach($categories as $category) : ?> <label><input type="checkbox" name="get_cats[]" value="<?php echo $category->slug; ?>"><?php echo $category->name; ?></label> <?php endforeach; ?> <h2>タグ</h2> <?php $post_tag_args = array( 'orderby' => 'name', 'order' => 'ASC', ); $post_tags = get_terms( 'post_tag', $post_tag_args ); foreach($post_tags as $post_tag) : ?> <label><input type="checkbox" name="get_tags[]" value="<?php echo $post_tag->slug; ?>"><?php echo $post_tag->name; ?></label> <?php endforeach; ?> <h2><?php _x( 'Search for:', 'label' ); ?>キーワード</h2> <input type="text" value="<?php echo get_search_query(); ?>" name="s" id="s" placeholder="キーワードを入力してください" /> <input type="submit" value="検索" /> </form>
search.php
<?php get_header(); ?> <?php $s = $_GET['s']; $get_cats = $_GET['get_cats']; $get_tags = $_GET['get_tags']; if($get_cats) { $tax_ary[] = array( 'taxonomy' => 'category', 'field' => 'slug', 'terms' => $get_cats, 'operator' => 'IN', //ANDかIN ); } if($get_tags) { $tax_ary[] = array( 'taxonomy' => 'post_tag', 'field' => 'slug', 'terms' => $get_tags, 'operator' => 'IN', //ANDかIN ); } ?> <?php if (!($s || $get_cats || $get_tags)): ?> <p>検索条件を指定してください</p> <?php get_search_form(); ?> <?php else: ?> <h1>検索結果</h1> <?php if(is_array($get_cats)) { echo '<p>カテゴリー:'; foreach ($get_cats as $val) { $p_term = get_term_by('slug', $val, 'category'); echo $p_term->name; if ($val !== end($get_cats)) { echo ', '; } } echo '</p>'; } ?> <?php if(is_array($get_tags)) { echo '<p>タグ:'; foreach ($get_tags as $val) { $s_term = get_term_by('slug', $val, 'post_tag'); echo $s_term->name; if ($val !== end($get_tags)) { echo ', '; } } echo '</p>'; } ?> <?php if($s) { echo '<p>キーワード:'.$s.'</p>'; } ?> <?php $my_query = new WP_Query( array( 'paged' => get_query_var('paged'), 'post_type' => 'post', 'tax_query' => $tax_ary, 'relation' => 'AND', //ANDかOR 's' => $s, )); ?> <?php if($my_query->have_posts() ) : ?> <ul> <?php while( $my_query->have_posts()) : $my_query->the_post(); ?> <li><a href="<?php the_permalink() ?>"><?php the_title(); ?></a> </li> <?php endwhile; ?> </ul> <?php else: ?> <p>結果が見つかりませんでした。</p> <?php endif; ?> <?php get_search_form(); ?> <?php endif; ?> <?php get_sidebar(); ?> <?php get_footer(); ?>
searchform.phpの解説
カテゴリー、タグの情報をget_terms関数で取得、foreachループでformのチェックボックスとして 一覧出力しています。
キーワード欄は通常の検索と同じ記述です。
カスタムタクソノミーやカスタム投稿の場合は?
get_terms( $taxonomies, $args )の$taxonomiesの部分にカスタムタクソノミー名を指定します。
$categories = get_terms( 'category', $category_args ); ↓↓↓ $taxonomies = get_terms( 'my_taxonomy', $taxonomy_args );
また、検索範囲をカスタム投稿に限定したい場合はformタグのactionのURIにカスタム投稿名(post_type)を指定します。
<form role="search" ... action="<?php echo esc_url(home_url('/')); ?>my_post/">
search.phpの解説
まず冒頭の$_GETで検索フォームでチェックされた項目及びフリーワードを取得しています。
$s = $_GET['s']; $get_cats = $_GET['get_cats']; $get_tags = $_GET['get_tags'];
もし何もチェックが無く、フリーワードも入力されていない場合は「検索条件を指定してください」というメッセージを出力します。
入力があれば、検索結果を表示します。
<?php if (!($s || $get_cats || $get_tags)): ?> <p>検索条件を指定してください</p> <?php get_search_form(); ?> <?php else: ?> <h1>検索結果</h1> //~省略~ <?php endif; ?>
チェックした項目とフリーワードを表示します。
この部分は無くてもいいのですが、検索条件を表示してあげる方が親切だと思います。
<h1>検索結果</h1> <?php if(is_array($get_cats)) { echo '<p>カテゴリー:'; foreach ($get_cats as $val) { $p_term = get_term_by('slug', $val, 'category'); echo $p_term->name; if ($val !== end($get_cats)) { echo ', '; } } echo '</p>'; } ?> <?php if(is_array($get_tags)) { echo '<p>タグ:'; foreach ($get_tags as $val) { $s_term = get_term_by('slug', $val, 'post_tag'); echo $s_term->name; if ($val !== end($get_tags)) { echo ', '; } } echo '</p>'; } ?> <?php if($s) { echo '<p>キーワード:'.$s.'</p>'; } ?>
WP_Queryを使って検索結果を取得します。
‘tax_query’パラメータ―には、チェックしたカテゴリーとタグを指定します。
冒頭の$_GETで取得しましたよね。
パラメータ―’s’はフリーワードです。
後はループで検索結果の投稿一覧を出力しています。
カスタムタクソノミーやカスタム投稿の場合は?
カスタムタクソノミーの場合は’tax_query’の’taxonomy’パラメータ―の部分にカスタムタクソノミー名を指定します。
$tax_ary[] = array( 'taxonomy' => 'my_taxonomy', ... );
AND / OR検索
カテゴリーやタグ同士の場合は、’tax_query’の’operator’にANDかIN(OR)で指定、カテゴリーとタグ間の場合はWP_Queryの’relation’にANDかORを指定します。
ソースコードにコメントを付けていますので確認してみてくださいね。
