ワードプレスのテーマtwentytwentyoneを基盤に、検索機能を自作する実装を行ったので、備忘録的にこの記事を残す。
環境情報
PHP:version 7.3.12
WordPress:version 5.6
WPテーマ:twentytwentyone
仕様
・検索対象の投稿タイプは search のみとする。
・フリーワードの検索対象は、タイトルと(本文と備考と)繰り返しフィールドの search_other_value の値の二つ
・「さらに条件を絞り込む」に指定があればキーワード検索と AND で繋ぎ絞り込む
・「さらに条件を絞り込む」の項目は、一つのブロック内は OR で繋ぎ、異なるブロック同士は AND で繋ぐ。
・地域の設定はカスタムタクソノミーでカテゴリーを作っているため、選択した地域名に該当するカテゴリーに属する会社名を検索に引っ掛ける。
・車種の登録はそれぞれ車種ごとに入力フィールド分かれており、台数が値として入っているため、「さらに条件を絞り込む」で任意の車種にチェックが入っていた場合には、その車種の台数が1以上の会社名を検索に引っ掛ける。
・対応言語の登録は、一つの入力フィールドでラジオボタンで登録する言語を選択しているため、配列の形で値が格納されている。そのため、「さらに条件を絞り込む」で任意の言語にチェックが入っていた場合には、その言語を配列に含む会社名を検索に引っ掛ける。
実装
検索ページ
今回は検索で表示させたい投稿の投稿タイプ名が search というもの一つだけだったので、検索ページを search のアーカイブページに設置しました。
<div class="search-box">
<form role="search" method="get" id="searchform" action="/" >
<input type="text" name="s" id="search-input" placeholder="○○内を検索" />
<div>
<label>さらに条件を絞り込む</label>
<div>
<label>エリア</label>
<select name="category" style="margin-top:20px;">
<option value="" selected>地域を選択</option>
<?php
$terms = get_terms( 'search_category',
array(
'parent' => 0,
'orderby' => 'id',
'order' => 'ASC'
)
);
foreach ( $terms as $term ) :
?>
<option value="<?php echo $term->slug; ?>"><?php echo $term->name; ?></option>
<?php endforeach; ?>
</select>
</div>
<div>
<label>こだわり</label><br>
<label><input type="checkbox" name="carmodel[]" value="general">一般タクシー</label><br>
<label><input type="checkbox" name="carmodel[]" value="higher">ハイヤー</label><br>
<label><input type="checkbox" name="carmodel[]" value="jumbo">ジャンボ</label><br>
<label><input type="checkbox" name="carmodel[]" value="welfare">福祉</label><br>
</div>
<div>
<label>外国語対応</label><br>
<label><input type="checkbox" name="language[]" value="english">英語</label><br>
<label><input type="checkbox" name="language[]" value="chinese">中国語</label><br>
<label><input type="checkbox" name="language[]" value="korean">韓国語</label><br>
</div>
</div>
<input type="hidden" name="post_type" value="search">
<button type="submit" accesskey="f" class="search-btn">検索</button>
</form>
</div>
functions.php での処理
//======================================================================
// 検索機能
//======================================================================
// 検索時の表示ファイルの設定
function custom_search_template( $template ) {
if ( is_search() ) {
$post_types = get_query_var( 'post_type' );
foreach ( ( array ) $post_types as $post_type )
$templates[] = "search-{$post_type}.php";
$templates[] = 'search.php';
$template = get_query_template( 'search', $templates );
}
return $template;
}
add_filter( 'template_include', 'custom_search_template' );
// キーワード検索に特定のカスタムフィールドを追加
function custom_search($search, $wp_query) {
global $wpdb;
if (!$wp_query->is_search) return $search;
if (!isset($wp_query->query_vars)) return $search;
$search_words = explode(' ', isset($wp_query->query_vars['s']) ? $wp_query->query_vars['s'] : '');
if ( count($search_words) > 0 ) {
$search = '';
$search .= "AND post_type = 'search'"; // 投稿タイプ名を設定
for ( $i = 0; $i <= 9; $i++ ) {
$custom_field_array[] = '"search_other_' . $i . '_search_other_value"';
}
$custom_field_list = implode( ', ', $custom_field_array );
foreach ( $search_words as $word ) {
if ( !empty($word) ) {
$search_word = '%' . esc_sql( $word ) . '%';
$search .= " AND (
{$wpdb->posts}.post_title LIKE '{$search_word}'
OR {$wpdb->posts}.post_content LIKE '{$search_word}'
OR {$wpdb->posts}.ID IN (
SELECT distinct post_id
FROM {$wpdb->postmeta}
WHERE {$wpdb->postmeta}.meta_key IN (
{$custom_field_list}
) AND meta_value LIKE '{$search_word}'
)
) "; // INのカッコ内に対象としたいフィールド名をコンマ区切りで追加
}
}
}
return $search;
}
add_filter('posts_search','custom_search', 10, 2);
// 検索結果ページのメインクエリを変更
function change_search_main_query( $query ) {
// 指定したページとメインクエリの場合に限定
if ( $query->is_main_query() && ( $query->is_search() || isset( $_GET['category'] ) || isset( $_GET['carmodel'] ) || isset( $_GET['language'] ) ) ) {
$s = $_GET['s'];
$category = $_GET['category'];
$carmodel = $_GET['carmodel'];
$language = $_GET['language'];
// 地域
if ( $category ) {
$taxquerysp[] = array(
'taxonomy' => 'search_category',
'terms' => $category,
'include_children' => false,
'field' => 'slug',
'operator' => 'AND'
);
}
$metaquerysp = [
'relation' => 'AND',
];
// 車種
if ( $carmodel ) {
$sub_metaquerysp = [
'relation' => 'OR',
];
foreach ( $carmodel as $val ) {
$sub_metaquerysp[] = array(
'key' => 'search_' . $val,
'value' => 0,
'compare' => '>'
);
}
}
// 言語
if ( $language ) {
$sub_metaquerysp = [
'relation' => 'OR',
];
foreach ( $language as $val ) {
$sub_metaquerysp[] = array(
'key' => 'search_language',
'value' => $val,
'compare' => 'LIKE',
);
}
}
$metaquerysp[] = $sub_metaquerysp;
$query->set( 'post_type', 'search' );
$query->set( 'tax_query', $taxquerysp );
$query->set( 'meta_query', $metaquerysp );
$query->set( 's', $s );
}
}
add_action( 'pre_get_posts', 'change_search_main_query' );
検索結果ページ
<?php
if ( have_posts() ) :
while ( have_posts() ) : the_post();
?>
<!-- ループ内の処理を記述 -->
<?php
endwhile;
else :
?>
該当なし
<?php
endif;
?>