まずはAND検索とOR検索の違いについておさらいします。
・OR検索→いずれかの検索ワードが1つでも含まれていたらヒット
・AND検索→すべての検索ワードが含まれていればヒット
つまり・・・
検索対象:「吾輩は猫である」
検索ワード:「吾輩 犬」
この場合、OR検索はヒットしますが、AND検索ではヒット判定になりません。
WordPressでは、AND検索を行う仕様になっています。
あいまい検索とも言われたりします。
AND検索とOR検索をラジオボタンで切り替えられる検索ボックスを作ってみます。
AND検索とOR検索を自由に切り替えられる検索ボックス
大まかに説明すると、WordPressでは、検索は以下のような流れで行われています。
①URLの末尾にGET(のパラメーター)で検索ワードを設定
(hhttps://hiyo-code.com/?s=hiyoko のように)
②パラメーターをもとにSQL検索クエリを作成
③データベースに対してSQLを実行、レスポンスを受け取る
④受け取ったデータ(ヒットした投稿)を一覧表示
AND検索か、OR検索かは②の処理内で決まりますので、こちらの処理を書き換えて行きたいと思います。
新たなフォームを作成する
テキストボックスの上にラジオボタンを設置し、こちらでANDとORを切り替えられるようにします。
ここで大事なのは、テキストボックスのname属性を“s”にすることです。WordPressでは、クエリ文字列の名前が「s」の値を検索ワードとみなします。
また、フォームにラジオボタンでパラメーターに「OR検索を実行したか、AND検索を実行したか」の情報を付与します。
また、検索が実行されて再度画面が表示されるときには、パラメーターに「AND」か「OR」が設定されています。これを元に初期値を決める処理を最初に入れています。
/**
* 自作の検索フォームを表示します
*/
function ShowOriginalSearchForm(){
$checkAND = "checked";
$checkOR = "";
//URLのクエリ文字列から初期選択を決定
if(isset($_GET['mode'])){
if($_GET['mode'] === 'OR'){
$checkAND = "";
$checkOR = "checked";
}
}
//HTML
echo '<form class="original_search_form" method="get" action="'.home_url().'">';
//ラジオボタン
echo '<p><input type="radio" name="mode" id="radio1" class="radiobtn" value="AND" '.$checkAND.'>';
echo '<label class="radiobtn_label" for="radio1">AND</label>';
echo '<input type="radio" id="radio2" name="mode" class="radiobtn" value="OR" '.$checkOR.'>';
echo '<label class="radiobtn_label" for="radio2">OR</label></p>';
//検索ボックス
echo '<div class="searchform">';
//テキストボックス
echo '<input type="text" name="s" value="'.get_search_query().'">';
//送信ボタン
echo '<input type="submit" value="検索">';
echo '</div>';
echo '</form>';
}
ついでに、それっぽいレイアウトを作ってみました。
/*フォーム全体*/
.customized_search_form{
box-sizing: border-box;
}
/*フォームのpタグ*/
.customized_search_form p{
margin-bottom:8px;
}
/*ラジオボタン*/
.radiobtn{
display: none;
}
/*ラジオボタンのラベル*/
.radiobtn_label{
font-size:0.9em;
margin-right:5px;
padding: 1px 10px 2px 10px;
color: #333;
text-align: center;
cursor: pointer;
background: #ccc;
border: none;
}
/*ラジオボタンのラベル(チェック)*/
.radiobtn:checked + .radiobtn_label {
background: skyblue;
}
/*検索エリア*/
.searchform{
display: flex;
height: 40px;
}
/*テキストボックス*/
.searchform input[type="text"]{
width:265px;
border: 1px solid;
}
/*検索ボタン*/
.searchform input[type="submit"]{
width: 55px;
margin-left:2px;
font-size:1em;
background: royalblue;
border: none;
color:white;
padding: 5px 5px 5px 5px;
}
アクションフィルタでSQL文を書き換える
「吾輩 猫」というワードでWordPressで検索を行った場合にMySQL上で実行されるクエリ文はこんな感じになっています。
SELECT SQL_CALC_FOUND_ROWS wp_posts.ID FROM wp_posts WHERE 1=1
AND (((wp_posts.post_title LIKE '%吾輩%') OR (wp_posts.post_excerpt LIKE '%吾輩%') OR (wp_posts.post_content LIKE '%吾輩%'))
AND ((wp_posts.post_title LIKE '%猫%') OR (wp_posts.post_excerpt LIKE '%猫%') OR (wp_posts.post_content LIKE '%猫%')))
AND wp_posts.post_type IN ('post', 'page', 'attachment') AND (wp_posts.post_status = 'publish' OR wp_posts.post_author = 1 AND wp_posts.post_status = 'private')
ORDER BY (CASE WHEN wp_posts.post_title LIKE '%吾輩 猫%' THEN 1 WHEN wp_posts.post_title LIKE '%吾輩%' AND wp_posts.post_title LIKE '%猫%' THEN 2 WHEN wp_posts.post_title LIKE '%吾輩%' OR wp_posts.post_title LIKE '%猫%' THEN 3 WHEN wp_posts.post_excerpt LIKE '%吾輩 猫%' THEN 4 WHEN wp_posts.post_content LIKE '%吾輩 猫%' THEN 5 ELSE 6 END),
wp_posts.post_date DESC LIMIT 0, 10
2行目と3行目を見れば分かる通り、検索ワードごとの条件文がANDで結合されているため、ここをORに書き換えればいいわけです。
ということで、検索が実行されたときにMySQL上で実行される前にクエリ文を書き換える処理を以下のように追加します。
/**
* 検索モードからクエリを変更
*/
function ChangeSearchMode($search){
//検索モードを確認し、クエリを変更
if(isset($_GET['mode'])){
if($_GET['mode'] === 'OR'){
$search = str_replace(')) AND ((', ')) OR ((', $search);
}
}
return $search;
}
//検索実行時フィルター
add_filter('posts_request', 'ChangeSearchMode');
フォームのほうで設定したラジオボタンの値を読み取り、ORだった場合にはクエリ文の対象箇所をANDからORに書き換えます。
これで、AND検索とOR検索が切り替えられる検索フォームを実現することができました。あとはウィジェットにするなり、functions.phpに直接記述して「ShowOriginalSearchForm」関数をテーマファイルの表示したい箇所に直接記述すればいいかと思います。
コメント
functions.phpに直接記述して「ShowOriginalSearchForm」関数をテーマファイルの表示したい箇所に直接記述するとのことですが、どう記述するのか教えて頂けると嬉しいです。
二ヶ所の記述については一か所目を記述して続けて二か所目をfunctions.phpに追記し、スタイルシートの記述はstyle.cssに追記するところまではできました。