※WordPress3.3.2を使用しています。
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_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必修! )