WordPressでの検索・絞り込み機能の実装方法
今回は、僕がお世話になっているハローメンターの課題として出された絞り込み機能を実装できたので解説します。ハローメンターでは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