📚

WordPressでの検索・絞り込み機能の実装方法

2024/08/04に公開

今回は、僕がお世話になっているハローメンターの課題として出された絞り込み機能を実装できたので解説します。ハローメンターではhtml,css,js,wordpress課題が出され、コードなどいろいろなFBを受けられます。ほかにも、運営会社がweb制作会社なので、代表の方が営業ロープレ(別料金かかります)などを行ってくれるプランも最近できました。

控えめに言って神!

※ここでは、本来やるべきこと(エスケープ処理やノンス、サニタイズなど)は大体省きます。説明が分かりにくくなるからです。

※私は駆け出しなので、稚拙でおかしい部分があるかもしれません。

実現したい事

  • 検索キーワード・もしくはエリアを選択し、どちらか一方がヒットすれば、それを表示する。
例)エリア選択を「関東」のみ

例)「銀座」「関東」で検索

つくってあそぼ・・・♠

前提

  • カスタムタクソノミーを使い、ショップのエリアを登録します。

見た目の準備

フォーム部分を実装していきます。

テンプレートパーツ化したshoplist-searchForm.phpです。

<div class="shoplist_search">
	<p class="shoplist_search_title">店舗検索</p>
	<form class="shoplist_form" method="get" action="<?php echo esc_url( home_url( '/' ) ); ?>">
		<input type="hidden" name="post_type" value="shoplist">
		<div class="shoplist_form_inner">
			<div class="shopist_form_block">
				<input placeholder="検索" class="shoplist_form_input" type="text" name="s"
					value="<?php the_search_query(); ?>">
				<select class="shoplist_form_select" name="area">
					<option value="">---</option>
					<?php
								$shopareas = get_terms(
									array(
										'taxonomy'   => 'shopareas',
										'hide_empty' => false,
									)
								);
								?>
					<?php
					foreach ( $shopareas as $area ) :
						$selected = ( isset( $_GET['area'] ) && $_GET['area'] == $area->slug ) ? 'selected="selected"' : '';
						?>
					<option value="<?php echo esc_attr( $area->slug ); ?>" <?php echo esc_attr( $selected ); ?>>
						<?php echo esc_html( $area->name ); ?>
					</option>
					<?php endforeach; ?>
				</select>
			</div>

			<button class="shoplist_form_button" type="submit">検索</button>
		</div>
	</form>
</div>

いろいろ書いてありますが、ここでのポイントは、

<input type="hidden" name="post_type" value="shoplist">
<div class="shopist_form_block">
				<input placeholder="検索" class="shoplist_form_input" type="text" name="s"
					value="<?php the_search_query(); ?>">
				<select class="shoplist_form_select" name="area">
					<option value="">---</option>
					<?php
								$shopareas = get_terms(
									array(
										'taxonomy'   => 'shopareas',
										'hide_empty' => false,
									)
								);
								?>
					<?php
					foreach ( $shopareas as $area ) :
						$selected = ( isset( $_GET['area'] ) && $_GET['area'] == $area->slug ) ? 'selected="selected"' : '';
						?> 
					<option value="<?php echo esc_attr( $area->slug ); ?>" <?php echo esc_attr( $selected ); ?>>
						<?php echo esc_html( $area->name ); ?>
					</option>
					<?php endforeach; ?>
				</select>
			</div>

です。

  • <input type="hidden" name="post_type" value="shoplist">で、投稿タイプを指定します。
    今回は、カスタム投稿タイプで作ったshoplistを指定します。

  • 次のinputで検索ワードを、selectボックスの中に、option(北海道や関東)を入れます。
    inputにはvalue="<?php the_search_query(); ?>"がありますが、これは、ページが遷移しても検索ワードを表示させるためです。

  • $shopareasにget_termsで、タクソノミのタームを取得し格納します。hide_empty⇒falseは、これがないと、記事がないタームは表示されません。「北海道、関東、九州沖縄」のタームにしか記事を登録してないので、hide_emptyがないとこの三つしかセレクトボックスに表示されません。ほかのエリアも表示したいので、falseにしています。

  • foreachでタクソノミのshopareasを回して、optionを自動生成しています。

  • 下記の記述で、検索後(ページ遷移後)も選んだエリアを表示する

    $selected = ( isset( $_GET['area'] ) && $_GET['area'] == $area->slug ) ? 'selected="selected"' : '';
    						?> 
    

    上記の記述は、もし検索されたareaが、optionの中のareaと一致するか?を判定し、一致するなら

    selected="selected"を代入します。

    そして、

    <option value="<?php echo esc_attr( $area->slug ); ?>" <?php echo esc_attr( $selected ); ?>>
    <?php echo esc_html( $area->name ); ?>
    </option>
    

    上記のように、selected属性を付与します。

  • 一応scssものっけときます。詳しくは触れません。

SCSS

.shoplist_form {
   margin-top: 16px;
}
.shoplist_form_input {
   border: 1px solid #ddd;
   padding: 4px;
   width: 100%;
   @include g.mq() {
      padding: 8px;
   }
}

.shoplist_form_button {
   background-color: #333;
   font-weight: bold;
   padding: 4px 24px;
   color: var(--bg-white);
   margin-left: auto;
   flex-shrink: 0;
   width: 90px;
   display: grid;
   place-items: center;
}

.shoplist_form_inner {
   display: flex;
   flex-wrap: wrap;
   gap: 16px;
   max-width: 550px;
   justify-content: space-between;
   @include g.mq(sm) {
      flex-wrap: nowrap;
   }
}

.shoplist_search_title {
   font-weight: bold;
   font-size: 22px;
}

.shoplist_form_select {
   border: 1px solid #ddd;
   padding: 4px 12px;
   min-width: 90px;
   @include g.mq() {
      padding: 8px 24px;
   }
}

.shopist_form_block {
   display: flex;
   gap: 16px;
   width: 100%;
   justify-content: space-between;
}

検索後のページ(検索された情報を元に$argsやクエリを作る)

<div class="u_ptb">
		<div class="l_container_lg">

			<?php get_template_part( 'templates/shoplist-searchForm' ); ?>
			<?php
			$args = array(
				'posts_per_page' => -1,
				's'              => isset( $_GET['s'] ) ? $_GET['s'] : '',
			);

			if ( isset( $_GET['area'] ) && $_GET['area'] !== '' ) {
				$args['tax_query'] = array(
					array(
						'taxonomy' => 'shopareas',
						'field'    => 'slug',
						'terms'    => $_GET['area'],
						'operator' => 'IN',
					),
				);
			}

			$shoplist_search_query = new WP_Query( $args );
			?>
			<?php if ( $shoplist_search_query->have_posts() ) : ?>
			<div class="shoplist_list">
				<?php
				while ( $shoplist_search_query->have_posts() ) :
					$shoplist_search_query->the_post();
					?>
					<?php get_template_part( 'templates/shoplist-item' ); ?>

				<?php endwhile; ?>
				<?php wp_reset_postdata(); ?>

			</div>
			<?php else : ?>
			<p class="c_empty">検索結果はありませんでした</p>
			<?php endif; ?>
		</div>
	</div>
  • templates/shoplist-itemのhtml,cssは省きます。
  • ポイントは以下です
<?php get_template_part( 'templates/shoplist-searchForm' ); ?>
			<?php
			$args = array(
				'posts_per_page' => -1,
				's'              => isset( $_GET['s'] ) ? $_GET['s'] : '',
			);

			if ( isset( $_GET['area'] ) && $_GET['area'] !== '' ) {
				$args['tax_query'] = array(
					array(
						'taxonomy' => 'shopareas',
						'field'    => 'slug',
						'terms'    => $_GET['area'],
						'operator' => 'IN',
					),
				);
			}

			$shoplist_search_query = new WP_Query( $args );
			?>
  • 最初の's' => isset( $_GET['s'] ) ? $_GET['s'] : '',で、普通にキーワード検索をかけます。
  • 下記のコードは、もしareaが選択されていれば、$args['tax_query']に新たに条件を追加する、というものです。
if ( isset( $_GET['area'] ) && $_GET['area'] !== '' ) {
				$args['tax_query'] = array(
					array(
						'taxonomy' => 'shopareas',
						'field'    => 'slug',
						'terms'    => $_GET['area'],
						'operator' => 'IN',
					),
				);
			}
  • タクソノミー(shopareas)のスラッグに検索をかけ、termsで指定したパラメータに一致するものを検索します。
  • operator: クエリ条件を指定します(例:IN は、terms に含まれるいずれかの値に一致する投稿を検索します)。(GPTより抜粋)
    • つまり、termsが複数あった場合に、どれか一つでもマッチしていれば、という意味です。

追記
'post_type' => 'shoplist',を$argsに設定してください。
<input type="hidden" name="post_type" value="shoplist">
を設定している場合でも、$argsに明示的にpost_typeを書かないと、すべての投稿タイプが検索に引っかかるようです。
試しに空欄のままで検索してみてください。
つまり、キーワード検索の部分でshoplist以外の投稿がヒットします。

以上!

これで、機能するはずです。

き、機能しなくても許して…

ハローメンター僕のツイッターをよろしくお願いします!

Discussion