カスタム投稿に絞り込み検索を実装する方法

WordPressのカスタム投稿で絞り込み検索を実装する機会があり、色々こねくり回してできたので備忘録として残しておきます。

今回の例は「美容院のサイトで、店舗を店舗名・地域から絞り込みできる機能」を想定しています。
キーワード検索とカスタムフィールドの値を使って絞り込みを行います。

↓検索エリアのイメージ

前提は次の通り。

  • 特定のカスタム投稿(店舗一覧)のみを検索範囲とする(投稿や個別ページは含まない)
  • search.phpは使わない
  • キーワード検索(店舗名)とプルダウン選択(地域)を使用
  • キーワードとプルダウンはAND条件
  • プルダウンはカスタムフィールドで指定した値から選択する

絞り込み機能は大きく分けて次の2つを実装します。

  • 検索フォームから検索クエリを取得
  • 検索結果を表示

これらの処理をカスタム投稿一覧(店舗一覧)ページであるarchive-shoplist.phpで行います。
(後でテンプレートファイルに分けますが)

Contents

検索フォームから検索クエリを取得

まずは検索クエリと検索フォームを実装します。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']に格納
  • $argsWP_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を忘れずに)

以上です!

Share
  • URLをコピーしました!
Contents