2012.06.01 「投稿記事だけ検索したい」に抜けている部分があったので修正しました。
検索フォームの設置
一つのテキストフォームだけで検索する場合は以下のコードを表示させたい位置に配置するだけですね。
wp template
<div id="search-box"> <form method="get" action="<?php bloginfo( 'url' ); ?>"> <input name="s" id="s" type="text" /> <input id="submit" type="submit" value="検索" /> </form> </div>
あとは「search.php」を作成して適当にループさせれば検索結果が表示されます。
投稿記事だけ検索したい
標準のサイト内検索は固定ページも検索範囲に含まれています。
投稿記事のみ検索したい場合は「functions.php」に下記のコードを追加してください。
functions.php
function custom_search($search, $wp_query) { //サーチページ以外だったら終了 if (!$wp_query->is_search) return; //投稿記事のみ検索 $search .= " AND post_type = 'post'"; return $search; } add_filter('posts_search','custom_search', 10, 2);
カスタム投稿タイプもこの「post_type」で判別しているので、カスタム投稿タイプ別に検索したい場合はこの部分を変更します。
検索関連のフックについて
MySQLを触ったことがある人ならお気づきでしょうが、「AND」といのはSQLのクエリです。
検索をカスタマイズするには「search.php」や固定ページでwp_queryを使用してカスタマイズする方法でもいけると思いますが、この記事ではすべて「functions.php」でSQLを直接変更する方法にします。
先ほどの「posts_search」はANDの部分のみを置き換えたり追加するフックです。
その他SQLのクエリに対応したフックは下記があります。
- posts_groupby
- posts_join
- posts_orderby
- posts_where
- posts_request
大部分を変更したい場合は「posts_request」を使用すればすべてのクエリを置き換えることができます。
カテゴリー&タグで絞り込み検索したい
指定したカテゴリー&タグに所属している「●●」という文字を含む記事の検索をしたい場合はフォームを修正するだけで対応できます。
以下の過去記事を参考にしてください。
WordPressでカテゴリー&タグを絞り込み検索をする
カテゴリーだけ(検索文字なし)で検索したい
検索は基本的にテキストボックスに文字列を入力しないと「archive.php」などが表示されてしまいます。
せっかくなのでカテゴリーのチェックボックスだけでも「search.php」を表示して検索したいですね。
「functions.php」に下記のコードを追加してください。
functions.php
function custom_search($search, $wp_query ) { //query['s']があったら検索ページ表示 if ( isset($wp_query->query['s']) ) $wp_query->is_search = true; return $search; } add_filter('posts_search','custom_search', 10, 2);
複数のカテゴリーで検索したい
先ほどのはセレクトボックスなので一つだけしかカテゴリーを選択できませんでしたが、複数のカテゴリーを選択できたら便利かもしれません。
フォーム部分は以下のようにすればチェックボックスになります。
<form method="get" action="<?php bloginfo( 'url' ); ?>"> <p>検索</p> <input name="s" id="s" type="text" /> <div> <h4>カテゴリー</h4> <?php $cats = get_categories(); foreach($cats as $cat) : echo '<label>' . '<input type="checkbox" value="' . $cat->cat_ID . '" name="cat[]" />' . esc_html($cat->cat_name) . '</label>'; endforeach; ?> </div> <input id="submit" type="submit" value="検索" /> </form>
これだけだとエラーが表示されてうまくいきません。
なにやら配列で渡してるのがいけないようなので、文字列にする必要があります。
「functions.php」に「request」というフックで「implode」で配列を文字列に変換すれば正常に動作します。
functions.php
function custom_request($query) { if (!empty($query['cat']) && array_key_exists('s', $query)){ $query['cat'] = implode(',', $query['cat']); } return $query; } add_filter( 'request', 'custom_request' );
複数のカテゴリーで絞り込み検索したい
先ほどの複数カテゴリーの検索はどちらかのカテゴリーに所属していればヒットする「OR検索」というものでした。
今度は両方のカテゴリーに所属している記事のみヒットするようにしてみましょう。
functions.php
function get_custom_field_posts_group($group) { if(isset($_REQUEST['cat'])) { global $wpdb; $group = $wpdb->prefix .'posts.ID HAVING count(*) >= '.count($_REQUEST['cat']); return $group; } } add_filter('posts_groupby', 'get_custom_field_posts_group');
日付で検索したい
新たに日付の入力フォームを用意します。
すごく簡略化しちゃってますが、実際はセレクトボックスとかjQueryUIとかで入力しやすくする必要があると思います。
とりあえずは「2012-05-01」みたいな感じで入力するとします。
<div> <h4>日付</h4> <input name="date_start" type="text"/> ~ <input name="date_end" type="text" /> </div>
先ほどの「custom_search」に下記に変更します。
functions.php
function custom_search($search, $wp_query) { //検索テキストが空でも検索ページを表示 if ( isset($wp_query->query['s']) ) $wp_query->is_search = true; //検索ページ以外だっ修了終了 if (!$wp_query->is_search) return; //日付で検索 if (!empty($_REQUEST['date_start']) && !empty($_REQUEST['date_end'])) { $start_date = "'" .date('Y-m-d', strtotime($_REQUEST['date_start'])). "'"; $end_date = "'" .date('Y-m-d', strtotime($_REQUEST['date_end'])). "'"; $search .= "AND DATE(post_date) BETWEEN {$start_date} AND {$end_date}"; } return $search; } add_filter('posts_search','custom_search', 10, 2);
カスタムフィールドで検索したい
たとえばカスタムフィールドの名前を「custom1」とします。
検索フォームに以下を追加します。
<div> <h4>カスタムフィールド</h4> <input name="meta_text" type="text" /> </div>
「posts_join」にフックして「wp_postmeta」テーブルを結合します。
functions.php
function custom_search_join($join){ if(!empty($_REQUEST['meta_text'])) { $join .= "INNER JOIN wp_postmeta ON (wp_posts.ID = wp_postmeta.post_id)"; } return $join; } add_filter( 'posts_join', 'custom_search_join' );
あとは先ほどの「custom_search」に以下を追加します。
入力したテキストと合致させたい場合は「=」ですが、「含む」の場合「LIKE」になります。
functions.php – custom_search
//カスタムフィールドで検索 if (!empty($_REQUEST['meta_text'])) { $meta_text = "'%" .mysql_real_escape_string($_REQUEST['meta_text']). "%'"; $search .= " AND wp_postmeta.meta_key = 'custom1' AND wp_postmeta.meta_value LIKE {$meta_text}"; }
カスタムフィールドの価格(数値)で検索
カスタムフィールドの検索ができればいろいろできますね。
例えば価格の検索をしてみます。
検索フォームに下記を追加します。
直接数値を入力させてもいいですが、セレクトメニューで選択するようにしてみました。
<div> <h4>価格</h4> <select name="price"> <option value="">選択してください。</option> <option value="1000">~1,000円</option> <option value="2000">1,000~2,000円</option> <option value="3000">2,000~3,000円</option> </select> </div>
「$_REQUEST[‘price’]」の場合でもカスタムフィールドと結合できるように変更します。
functions.php – custom_search_join
function custom_search_join($join){ if(!empty($_REQUEST['meta_text']) || !empty($_REQUEST['price'])) { $join .= "INNER JOIN wp_postmeta ON (wp_posts.ID = wp_postmeta.post_id)"; } return $join; } add_filter( 'posts_join', 'custom_search_join' );
「custom_search」に下記を追加します。
今回は1,000円単位なので取得した値からマイナス1,000をして範囲を指定しています。
functions.php – custom_search
if (!empty($_REQUEST['price'])) { $meta_price = intval($_REQUEST['price']); $mate_pricelow = $meta_price - 1000; $search .= " AND wp_postmeta.meta_key = 'price' AND wp_postmeta.meta_value BETWEEN {$mate_pricelow} AND {$meta_price} "; }
ちょっとやり散らかした感がありますが、以上です。
実際使うにはもう少し条件分岐が必要だったり、問題があったりするかもしれませんが、とっかかりに程度にはなるのかなとか。
また、これを機にMySQLをはじめてみようかなと思った方は最近改訂版が出た「基礎からのMySQL」がおすすめです。
基礎からのMySQL 改訂版 (プログラマの種シリーズ SE必修! )