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必修! )
