WordPressのカスタム投稿で絞り込み検索を実装する機会があり、色々こねくり回してできたので備忘録として残しておきます。
今回の例は「美容院のサイトで、店舗を店舗名・地域から絞り込みできる機能」を想定しています。
キーワード検索とカスタムフィールドの値を使って絞り込みを行います。
↓検索エリアのイメージ
前提は次の通り。
- 特定のカスタム投稿(店舗一覧)のみを検索範囲とする(投稿や個別ページは含まない)
- search.phpは使わない
- キーワード検索(店舗名)とプルダウン選択(地域)を使用
- キーワードとプルダウンはAND条件
- プルダウンはカスタムフィールドで指定した値から選択する
絞り込み機能は大きく分けて次の2つを実装します。
- 検索フォームから検索クエリを取得
- 検索結果を表示
これらの処理をカスタム投稿一覧(店舗一覧)ページであるarchive-shoplist.php
で行います。
(後でテンプレートファイルに分けますが)
検索フォームから検索クエリを取得
まずは検索クエリと検索フォームを実装します。archive-shoplist.phpに以下を記述します。
<?php
// 検索キーワードを取得
$search_keyword = isset($_GET['search_keyword']) ? sanitize_text_field($_GET['search_keyword']) : '';
// プルダウンの選択内容を取得
$selected_area = isset($_GET['selected_area']) ? sanitize_text_field($_GET['selected_area']) : '';
// 検索クエリ(ベース)を作成
$args = array(
'post_type' => 'shoplist', // 投稿タイプ
'posts_per_page' => -1, // 取得数(-1は全て)
);
// キーワード検索の内容を検索クエリに追加
if (!empty($search_keyword)) {
$args['s'] = $search_keyword;
}
// 選択した地域をmeta_queryに追加
if (!empty($selected_area)) {
$args['meta_query'] = array(
array(
'key' => 'area', // ACFのフィールド名
'value' => $selected_area, // フォームから取得した値
'compare' => '=' // 一致しているもの
),
);
}
// サブクエリで検索結果のデータを取得
$shoplist_query = new WP_Query($args);
?>
<!-- 表示部分 -->
<form class="search" method="get" action="">
<p class="search__title">店舗検索</p>
<div class="search__inner">
<input type="text" name="search_keyword" value="<?php echo esc_attr($search_keyword); ?>" class="c-form-text" placeholder="検索" />
<div class="c-form-select">
<select name="selected_area">
<option value="">--</option>
<?php $areas = get_field_object('area')['choices'];
foreach ($areas as $value => $label): ?>
<?php echo '<option value="' . esc_attr($value) . '" ' . selected($selected_area, $value, false) . '>' . esc_html($label) . '</option>'; ?>
<?php endforeach; ?>
</select>
</div>
<!-- 検索対象をshoplist内に限定 -->
<input type="hidden" name="post_type" value="<?php echo esc_html(get_post_type_object(get_post_type())->name); ?>">
<input type="submit" value="検索" class="c-form-submit-button">
</div>
</form>
上記では、
- キーワード:
input
タグに入力した内容を$args['s']
に格納 - プルダウン:
$args['meta_query']
に格納 $args
をWP_Query
の引数に渡す
をしています。
meta_query
はカスタムフィールドの絞り込みをする際に使用し、key
にACFの管理画面で指定したフィールド名、value
に絞り込みしたい値を指定します。
最終的にサブクエリに渡す条件$args
は以下のようになります。
$args = array(
"post_type" => "shoplist",
"posts_per_page" => -1,
"s" => "福岡",
"meta_query" => array(
array(
"key" => "area",
"value" => "九州沖縄",
"compare" => "="
),
));
検索結果を表示
検索結果はループで出力します。
<?php
if($shoplist_query->have_posts()):
while($shoplist_query->have_posts()): $shoplist_query->the_post(); ?>
<!-- ループで表示したい内容 -->
<?php endwhile;
wp_reset_postdata();
else: ?>
<p>該当する店舗がありません</p>
<?php endif; ?>
</div>
以上です。
コード分割
最後に、全体が長くなってきたので検索クエリ作成部分とフォームをテンプレートとして別ファイル(shoplist-search.php)に分けたいと思います。
【shoplist-search.php】
<?php
// 検索キーワードを取得
$search_keyword = isset($_GET['search_keyword']) ? sanitize_text_field($_GET['search_keyword']) : '';
// プルダウンの選択内容を取得
$selected_area = isset($_GET['selected_area']) ? sanitize_text_field($_GET['selected_area']) : '';
// 検索クエリ(ベース)を作成
$args = array(
'post_type' => 'shoplist', // 投稿タイプ
'posts_per_page' => -1, // 取得数(-1は全て)
);
// キーワード検索の内容を検索クエリに追加
if (!empty($search_keyword)) {
$args['s'] = $search_keyword;
}
// 選択した地域をmeta_queryに追加
if (!empty($selected_area)) {
$args['meta_query'] = array(
array(
'key' => 'area', // ACFのフィールド名
'value' => $selected_area, // フォームから取得した値
'compare' => '=' // 一致しているもの
),
);
}
// サブクエリで検索結果のデータを取得
$shoplist_query = new WP_Query($args);
?>
<!-- 表示部分 -->
<form class="search" method="get" action="">
<p class="search__title">店舗検索</p>
<div class="search__inner">
<input type="text" name="search_keyword" value="<?php echo esc_attr($search_keyword); ?>" class="c-form-text" placeholder="検索" />
<div class="c-form-select">
<select name="selected_area">
<option value="">--</option>
<?php $areas = get_field_object('area')['choices'];
foreach ($areas as $value => $label): ?>
<?php echo '<option value="' . esc_attr($value) . '" ' . selected($selected_area, $value, false) . '>' . esc_html($label) . '</option>'; ?>
<?php endforeach; ?>
</select>
</div>
<!-- 検索対象をshoplist内に限定 -->
<input type="hidden" name="post_type" value="<?php echo esc_html(get_post_type_object(get_post_type())->name); ?>">
<input type="submit" value="検索" class="c-form-submit-button">
</div>
</form>
【archive-shoplist.php】
<?php get_header(); ?>
<!-- page-shoplist -->
<div class="page-shoplist section container-l">
<!-- 検索フォームを呼び出し -->
<?php include 'shoplist-search.php'; ?>
<div class="page-shoplist__inner">
<?php
if($shoplist_query->have_posts()):
while($shoplist_query->have_posts()): $shoplist_query->the_post(); ?>
<!-- ループで表示したい内容 -->
<?php endwhile;
wp_reset_postdata();
else: ?>
<p>該当する店舗がありません</p>
<?php endif; ?>
</div>
</div>
<!-- /.page-shoplist -->
<?php get_footer(); ?>
shoplist-search.php
を呼び出しているのは
<?php include 'shoplist-search.php'; ?>
の部分です。
WordPressではテンプレート呼び出しのタグにget_template_part()
がありますが、これだと呼び出し元・先のファイルで定義された変数が使えません。
今回の例だとshoplist-search.php
で定義している$shoplist_query
を呼び出し元のarchive-shoplist.php
でも使っているので、phpの関数include
で処理しています。(拡張子.phpを忘れずに)
以上です!