WordPressの検索機能をプラグイン無しで拡張する
公開日:2018年6月29日
WordPress標準の検索機能は、タイトルと本文を対象としたキーワード検索です。機能を拡張するプラグインも存在しますが、ここではプラグインを使わずに、カスタムタクソノミーとカスタムフィールドを検索対象として追加する実装方法を解説します。
【コンテンツ】
- WordPressの検索機能のおさらい
- この記事で実装する検索機能の概要
- 検索キーワード未入力時のリダイレクト処理を追加する
- 検索対象を該当するカスタム投稿に絞り込む
- 検索フォームをコーディングする
- 検索結果ページをコーディングする
【記事執筆時の環境】
Windows 10 Pro 64bit
WordPress 4.9.6
MariaDB 10.1.31
PHP 7.1.15
WordPressの検索機能のおさらい
まずは、標準で搭載されているWordPressの検索機能について、おさらいの意味で説明します。
- 検索条件は、キーワードのみです。
- キーワードが含まれているか対象とするのは本文とタイトルです。抜粋に入力した文章は対象としません。カスタムフィールドも検索対象とするには、「functions.php」にフィルターフックを記述することで実現できますが、簡単に実現したいなら、プラグイン「Search Everything」や「Relevanssi - A Better Search」を使うこともできます。
- 検索対象となるページは、投稿記事と固定ページです。固定ページを除くとか、特定のカスタム投稿だけを検索対象としたい場合は、「posts_search」というフィルターを使い「functions.php」に記述することで実現できます。もちろんプラグインでもできます。
- 検索結果を表示するページは、「search.php」です。「search.php」が存在しない場合は、「index.php」になります。
- 検索条件が未入力で検索をかけると、「search.php」ではなく「index.php」を表示します。その場合でも「search.php」を表示したい場合は、リダイレクトをする記述を「functions.php」内にします。
- 検索フォームを呼び出す関数として、「get_search_form()」があります。「get_search_form()」の動作としては、「searchform.php」が存在する場合はその内容を読み込み、存在しない場合は、組み込みの HTMLコードを出力します。
この記事で実装する検索機能の概要
サンプルとして、パソコン教室で開催している講座を検索する機能を実装します。
各講座の情報は、カスタム投稿で入力しています。
パソコン講座の検索は、以下の項目で AND検索できるようにします。
- 講座カテゴリー
カスタムタクソノミーで登録しており、検索はチェックボックスで選択します。 - 開催曜日
カスタムフィールドで登録しており、検索はチェックボックスで選択します。 - 開始時間
カスタムフィールドで登録しており、検索はチェックボックスで選択します。 - キーワード
講座タイトルと本文にテキストフィールドに入力したキーワードが含まれているか検索します。こちらは WordPress の標準機能を使います。
検索機能を提供するプラグインとして、「WP Custom Fields Search」や「FE Advanced Search」がありますが、カスタマイズするのに制限があり応用がきかなくなりますので、今回は使いません。
また、検索対象を指定したり拡張するプラグイン「Search Everything」や「Relevanssi - A Better Search」も使いません。
それらのプラグインは便利ですが、WordPress のバージョンが変わったり、検索条件を変えると動作がおかしくなることもあったので、現在私は限定された用途でしか使わないことにしています。
ただし、カスタムフィールドを登録するのに、プラグイン「Advanced Custom Fields」を使っています。
検索キーワード未入力時のリダイレクト処理を追加する
WordPress のキーワード検索では、input要素の name属性に "s" を指定し GET で送ります。この "s" に値が入っている時は、「search.php」を表示しますが、値が入っていない時は、「index.php」を表示してしまいます。
今回の検索仕様ではキーワードが空欄ということも考えられるし、検索結果表示の処理は「search.php」だけで行いたいので、キーワードが未入力でも「search.php」が表示されるよう、リダイレクト処理を「functions.php」に記述します。
1 2 3 4 5 6 7 8 |
// 検索キーワードが未入力時にsearch.phpにリダイレクトする function my_set_redirect_template(){ if (isset($_GET['s']) && empty($_GET['s'])) { include(TEMPLATEPATH . '/search.php'); exit; } } add_action('template_redirect', 'my_set_redirect_template'); |
検索対象を該当するカスタム投稿に絞り込む
検索結果に表示したいのは、カスタム投稿で登録している「講座情報」だけですので、カスタム投稿タイプ "course" だけを検索対象とするよう、「functions.php」に記述します。
1 2 3 4 5 6 7 |
// 検索する時に講座情報のみを検索対象とする function my_set_site_search_post($search, $wp_query) { if (!$wp_query->is_search) return; $search .= " AND (post_type = 'course')"; return $search; } add_filter('posts_search','my_set_site_search_post', 10, 2); |
検索フォームをコーディングする
ここまでできたら、あとは検索フォームと検索結果ページのコーディングです。
まずは検索フォームからコーディングしてみます。
検索フォームは、コードを「searchform.php」の中に記述し、呼び出すときは「get_search_form()」を使う仕組みが WordPress標準で用意されていますが、WordPress組み込みのコードを利用しない場合は特にこだわる必要はありません。
フォームを設置するページに直接記述してもいいですし、別の名前でテンプレートパーツを作成し、それを呼び出しても全く同じです。
まずは、基本となるキーワード検索の部分をコーディングすると、下記のようになります。
なお、サンプルコードは、スタイルは全く考えていません。実際のサイトでは、table要素などを使いCSSできれいに整えます。
1 2 3 4 5 6 7 8 9 |
<form method="get" id="searchform" action="<?php echo home_url( '/' ); ?>"> <div> <!-- キーワード検索 --> <p>キーワード:</p> <input type="text" name="s" id="s"> </div> <div> <!-- 送信ボタン --> <input type="submit" id="searchsubmit" value="検索"> </div> </form> |
次に、講座カテゴリーでの検索部分を、チェックボックスで実装します。
講座カテゴリーは、カスタムタクソノミー名 'coursecategory' で登録していますので、ループで回してそれらをリスト表示しています。
複数選択可能となりますので、input要素の name属性は配列にします。
講座カテゴリー検索部分を加えたコードは下記になります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
<form method="get" id="searchform" action="<?php echo home_url( '/' ); ?>"> <div> <!-- 講座カテゴリー検索 --> <p>講座カテゴリー(複数選択可):</p> <ul> <?php $taxonomy_name = 'coursecategory'; $taxonomys = get_terms($taxonomy_name); if(!is_wp_error($taxonomys) && count($taxonomys)): foreach($taxonomys as $taxonomy): $tax_posts = get_posts(array('post_type' => 'course', 'taxonomy' => $taxonomy_name, 'term' => $taxonomy->slug ) ); if($tax_posts): ?> <li><label><input type="checkbox" name="course_cat[]" value="<?php echo $taxonomy->slug; ?>"><?php echo $taxonomy->name; ?></label></li> <?php endif; endforeach; endif; ?> </ul> </div> <div> <!-- キーワード検索 --> <p>キーワード:</p> <input type="text" name="s" id="s"> </div> <div> <!-- 送信ボタン --> <input type="submit" id="searchsubmit" value="検索"> </div> </form> |
同様に、開催曜日と開始時間での検索部分を、チェックボックスで実装します。
value属性には、カスタムフィールドにおける選択肢の値を入れます。
検索フォームの完成コードは下記になります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
<form method="get" id="searchform" action="<?php echo home_url( '/' ); ?>"> <div> <!-- 講座カテゴリー検索 --> <p>講座カテゴリー(複数選択可):</p> <ul> <?php $taxonomy_name = 'coursecategory'; $taxonomys = get_terms($taxonomy_name); if(!is_wp_error($taxonomys) && count($taxonomys)): foreach($taxonomys as $taxonomy): $tax_posts = get_posts(array('post_type' => 'course', 'taxonomy' => $taxonomy_name, 'term' => $taxonomy->slug ) ); if($tax_posts): ?> <li><label><input type="checkbox" name="course_cat[]" value="<?php echo $taxonomy->slug; ?>"><?php echo $taxonomy->name; ?></label></li> <?php endif; endforeach; endif; ?> </ul> </div> <div> <!-- 開催曜日検索 --> <p>開催曜日(複数選択可):</p> <ul> <li><label><input type="checkbox" name="open_days[]" value="月">月</label></li> <li><label><input type="checkbox" name="open_days[]" value="火">火</label></li> <li><label><input type="checkbox" name="open_days[]" value="水">水</label></li> <li><label><input type="checkbox" name="open_days[]" value="木">木</label></li> <li><label><input type="checkbox" name="open_days[]" value="金">金</label></li> <li><label><input type="checkbox" name="open_days[]" value="土">土</label></li> <li><label><input type="checkbox" name="open_days[]" value="日">日</label></li> </ul> </div> <div> <!-- 開始時間検索 --> <p>開始時間(複数選択可):</p> <ul> <li><label><input type="checkbox" name="start_time[]" value="午前中">午前中</label></li> <li><label><input type="checkbox" name="start_time[]" value="12時~">12時~</label></li> <li><label><input type="checkbox" name="start_time[]" value="15時~">15時~</label></li> <li><label><input type="checkbox" name="start_time[]" value="18時~">18時~</label></li> </ul> </div> <div> <!-- キーワード検索 --> <p>キーワード:</p> <input type="text" name="s" id="s"> </div> <div> <!-- 送信ボタン --> <input type="submit" id="searchsubmit" value="検索"> </div> </form> |
検索結果ページをコーディングする
検索結果ページは、「search.php」ですので、その中にコードを記述します。
最終的には検索条件に合致した記事を「WP_Query()」で取得し表示するのですが、問題はどうパラメータを渡すかです。
また、検索条件に合致した記事がない場合の処理と、検索条件が何も入力されていない処理も記述する必要があります。
処理の流れとしては、まずクエリストリングで渡されている文字列を配列変数に代入します。
そして、それらの配列変数を使って、「WP_Query()」に渡すパラメータを定義します。
あとはループで回して、検索結果として出てくる記事のタイトルや内容を表示します。
それではまず、クエリストリングスの文字列を配列変数に代入する部分です。
注意点としては、講座カテゴリーと開始時間は講座につき1つしか選択されていませんが、開催曜日は複数選択されているケースがあることです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
<?php $s = $_GET['s']; $course_cat = $_GET['course_cat']; $open_days = $_GET['open_days']; $start_time = $_GET['start_time']; if($course_cat){ $course_cat_query[] = array( 'taxonomy'=>'coursecategory', 'terms'=> $course_cat, 'include_children'=>false, 'field'=>'slug', 'operator'=>'IN' ); } if($open_days){ foreach($open_days as $val){ $open_days_query[] = array( 'key'=>'open-days', 'value'=> $val, 'compare' => 'LIKE', ); } } $open_days_query['relation'] = 'OR'; if($start_time){ foreach($start_time as $val){ $start_time_query[] = array( 'key'=>'start-time', 'value'=> $val, ); } } $start_time_query['relation'] = 'OR'; ?> |
次に、入力された検索条件を表示する部分を作ってみます。もし検索条件が何も入力されていなかったらメッセージを表示するようにします。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
<?php if (empty($_GET['s']) && empty($_GET['course_cat']) && empty($_GET['open_days']) && empty($_GET['start_time'])) { ?> <p>検索条件が入力されていません。</p> <?php } else { ?> <p>< 検索条件 ><br> <?php if (is_array($course_cat)) { ?>講座カテゴリー:<?php foreach($course_cat as $val){ if ($val === end($course_cat)) { echo get_term_by('slug',$val,"coursecategory")->name; } else { echo get_term_by('slug',$val,"coursecategory")->name.", "; } } echo "<br>"; } ?> <?php if (is_array($open_days)) { ?>開催曜日:<?php foreach($open_days as $val){ if ($val === end($open_days)) { echo $val; } else { echo $val.", "; } } echo "<br>"; } ?> <?php if (is_array($start_time)) { ?>開始時間:<?php foreach($start_time as $val){ if ($val === end($start_time)) { echo $val; } else { echo $val.", "; } } echo "<br>"; } ?> <?php if ($s) { ?>キーワード:<?php echo $s; ?><br><?php } ?> <br> </p> <?php } ?> |
最後は、「WP_Query()」に渡すパラメータを定義し、ループで回して記事情報を表示します。
検索条件に合致する記事が1つもない場合は、メッセージを表示する処理も加えます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
<?php $args = array( 'posts_per_page' => -1, 'post_type' => 'course', 'tax_query' => $course_cat_query, 'meta_query' => array ( 'relation' => 'AND', $open_days_query, $start_time_query, ), 's' => $s, ); $my_query = new WP_Query( $args ); if ( $my_query->have_posts() ) : while ( $my_query->have_posts() ) : $my_query->the_post(); ?> <p><?php the_title(); ?></p> <?php endwhile; else : ?> <p>検索条件にヒットしたページがありませんでした。</p> <?php endif; wp_reset_postdata(); ?> |
これで検索結果ページのコーディングが終了しました。あとはCSSでスタイルを整えれば完成です。
最後に、ここで説明した検索結果ページのすべてのコードを示します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 |
<?php $s = $_GET['s']; $course_cat = $_GET['course_cat']; $open_days = $_GET['open_days']; $start_time = $_GET['start_time']; if($course_cat){ $course_cat_query[] = array( 'taxonomy'=>'coursecategory', 'terms'=> $course_cat, 'include_children'=>false, 'field'=>'slug', 'operator'=>'IN' ); } if($open_days){ foreach($open_days as $val){ $open_days_query[] = array( 'key'=>'open-days', 'value'=> $val, 'compare' => 'LIKE', ); } } $open_days_query['relation'] = 'OR'; if($start_time){ foreach($start_time as $val){ $start_time_query[] = array( 'key'=>'start-time', 'value'=> $val, ); } } $start_time_query['relation'] = 'OR'; ?> <?php if (empty($_GET['s']) && empty($_GET['course_cat']) && empty($_GET['open_days']) && empty($_GET['start_time'])) { ?> <p>検索条件が入力されていません。</p> <?php } else { ?> <p>< 検索条件 ><br> <?php if (is_array($course_cat)) { ?>講座カテゴリー:<?php foreach($course_cat as $val){ if ($val === end($course_cat)) { echo get_term_by('slug',$val,"coursecategory")->name; } else { echo get_term_by('slug',$val,"coursecategory")->name.", "; } } echo "<br>"; } ?> <?php if (is_array($open_days)) { ?>開催曜日:<?php foreach($open_days as $val){ if ($val === end($open_days)) { echo $val; } else { echo $val.", "; } } echo "<br>"; } ?> <?php if (is_array($start_time)) { ?>開始時間:<?php foreach($start_time as $val){ if ($val === end($start_time)) { echo $val; } else { echo $val.", "; } } echo "<br>"; } ?> <?php if ($s) { ?>キーワード:<?php echo $s; ?><br><?php } ?> <br> </p> <?php $args = array( 'posts_per_page' => -1, 'post_type' => 'course', 'tax_query' => $course_cat_query, 'meta_query' => array ( 'relation' => 'AND', $open_days_query, $start_time_query, ), 's' => $s, ); $my_query = new WP_Query( $args ); if ( $my_query->have_posts() ) : while ( $my_query->have_posts() ) : $my_query->the_post(); ?> <p><?php the_title(); ?></p> <?php endwhile; else : ?> <p>検索条件にヒットしたページがありませんでした。</p> <?php endif; wp_reset_postdata(); ?> <?php } ?> |
スポンサーリンク