ダリの雑記:WEBプログラム版

WordPressの検索機能をカスタマイズ

WordPressの検索の欠点として

というものがあります。

最近は内容フィールドは使用せず、カスタムフィールドに中身を入れるといった場合もあるので、これでは大変不便です。

ということで、検索機能をカスタマイズし、これらからも引っ張ってくるようにします。(ついでに抜粋からも)

なお、検索処理のカスタマイズは「pre_get_posts」をフックした関数にて行います。

pre_get_postsについては、こちらをご覧ください(query_postsを捨てよ、pre_get_postsを使おう【追記あり】【報告あり】)。

functions.phpに下記を追加します。
※pre_get_postsをフックした関数がすでに存在していている場合は、うまく編集してください。

[PHP]
function my_pre_get_posts($query) {
//管理画面には適応しない
if ( is_admin() || ! $query->is_main_query() )
return;

//検索画面の場合
if($query->is_search()){
global $wpdb;

$keywords = get_search_query();
if($keywords){

$keywords = str_replace(" ", " ", $keywords);
$keyword_array = explode(" ", $keywords);
$post_ids = array();
$post_ids_exists = array();
foreach($keyword_array as $keyword){
$post_ids_meta = array(); //カスタムフィールド
$post_ids_post = array(); //タイトル・内容
$post_ids_term = array(); //カテゴリー

if($keyword){
$keyword = '%' . like_escape( $keyword ) . '%';

//カスタムフィールド内を検索
$post_ids_meta = $wpdb->get_col( $wpdb->prepare( "
SELECT DISTINCT post_id FROM {$wpdb->postmeta}
WHERE meta_value LIKE '%s'
", $keyword ) );

//タイトルと内容・抜粋から検索
$post_ids_post = $wpdb->get_col( $wpdb->prepare( "
SELECT DISTINCT ID FROM {$wpdb->posts}
WHERE post_title LIKE '%s'
OR post_content LIKE '%s'
OR post_excerpt LIKE '%s'
", $keyword, $keyword, $keyword ) );

//カテゴリー名から検索
$term_ids = $wpdb->get_col( $wpdb->prepare( "
SELECT DISTINCT term_id FROM {$wpdb->terms}
WHERE name LIKE '%s'
", $keyword) );
//ヒットしたカテゴリーが所属する投稿
if($term_ids){
$term_id = implode(",", $term_ids);
$post_ids_term = $wpdb->get_col( $wpdb->prepare( "
SELECT DISTINCT object_id FROM {$wpdb->term_relationships}
WHERE term_taxonomy_id IN (%s)
", $term_id) );
}

//各処理で取得した投稿IDをマージする。
$post_ids_tmp = array();
$post_ids_tmp = array_merge($post_ids_meta, $post_ids_post, $post_ids_term);

//重複している投稿IDのみ抜き出す(AND検索のため)
if($post_ids_tmp){
//検索ワード1つ目の場合、$post_ids_existsのキーに投稿IDを入れていく(内容はtrue)
if(empty($post_ids_exists)){
foreach($post_ids_tmp as $post_id){
$post_ids_exists[$post_id] = 1;
}
}
//検索ワード2つ目以降の場合
else{
//○つ目の投稿IDを$post_ids_exists_tmpキーに入れていく(内容はtrue)
$post_ids_exists_tmp = array();
foreach($post_ids_tmp as $post_id){
$post_ids_exists_tmp[$post_id] = 1;
}

//1つ目の$post_ids_existsと、○つ目の$post_ids_exists_tmpとを比較し、存在しない場合はunsetする。
foreach($post_ids_exists as $post_id => $value){
if($post_ids_exists_tmp[$post_id] != 1){
unset($post_ids_exists[$post_id]);
}
}
}
}
}
}

//まとめた$post_ids_existsのキー(投稿ID)を、内容に移す
if($post_ids_exists){
foreach($post_ids_exists as $post_id => $value){
$post_ids[] = $post_id;
}
}
if($post_ids){
$query->set('post__in', $post_ids);
}else{
$query->set('post__in', array(0));
}

}else{
$query->set('post__in', array(0));
}
$query->set('s', ''); //本来の検索は邪魔になるので削除しておく
}
}
add_action( 'pre_get_posts', 'my_pre_get_posts' );
[/PHP]

最後に、

[PHP]
$query->set('s', '');
[/PHP]

を行っているため、検索結果ページで、$sやget_query_var('s')から検索ワードを取得できなくなっています。

そのため、search.phpのget_header()の前に

[PHP]
$wp_query->query_vars["s"] = $wp_query->query["s"];
[/PHP]

を追記してください。
これで$sやget_query_var('s')を使って検索ワードを取得できるようになります。

しかし結構ごつい処理をしてるので重くなりそうな気も・・・大丈夫かな。

参考サイト

モバイルバージョンを終了