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