【徹底解説】WordPressで絞り込み検索を作る方法

WordPressには標準で記事の絞り込み機能があります。

例えば、サイドバーのウィジェットにカテゴリーやタグの一覧を表示して、特定のカテゴリーやタグが割り当てられた記事だけを簡単に表示できます。

しかし、「カテゴリーAまたはカテゴリーBが割り当てられた記事を表示」、「カテゴリーAとタグCの両方が割り当てられた記事を表示」といったように、複雑な絞り込み検索はできません。

この記事では、WordPressで本格的な絞り込み検索を作る方法を紹介します。

なお、プログラミングやデザインが苦手な方は、絞り込み検索を使えるテーマを選べば、大幅に作業時間を減らせますし、バグが発生する可能性が下がります。

絞り込み検索を使えるWordPressテーマ

例えば、非常に高機能な検索ができるテーマとして人気なのが「GENSEN」です。

キーワード、カテゴリー、タグなどを使って複雑な絞り込み検索ができます。

しかも、キーワード検索ではAND検索(かつ)やOR検索(または)という条件を選択できて、検索結果は新しい順や閲覧数順などで並び替えができます。

デザイン自体も素晴らしいので、このレベルのサイトを自分で作ろうと思えば膨大な時間がかかると思います。

その他のテーマは、以下の記事をお読みください。

絞り込み検索のデモサイト

参考として、この記事の内容をベースに一部をカスタマイズしながら、「WordPressテーマギャラリー」という絞り込み検索のデモサイトを作りました。

WordPressの絞り込み検索のデモサイト

検索フォームをサイドバーに設置しているので、毎回検索ページに戻る必要はありません。

また、サイト全体のページ数が多くはないので、検索結果ページを作らずに、検索フォームの下に表示しています。

検索結果の記事をクリックしたときは、検索条件と検索結果を残しています。そのため、検索結果の記事を順番にクリックして閲覧できるようになっています。

ただし、ヘッダーやフッターのリンクなど検索結果の記事以外がクリックされたときは、検索結果以外から情報を探す、もしくは新たな検索条件で探すと判断して、保持している検索条件と検索結果をクリアします。

その他、補足情報は以下の通りです。

  • WordPressのテーマは「SWELL」を使用して作業時間を短縮。
  • 検索条件は、カテゴリー、タグ、カスタムタクソノミーを使います。
  • 検索処理はAjaxを使って非同期に行います。
  • 検索中はローディングアイコンを表示します。
  • 検索結果が多いときはページャーを表示します。
  • おまけとして、検討中の記事を掲載するお気に入り機能を実装しました。
注意
デモサイトということもあってバグがあるかもしれません。特にGoogle Chrome以外のブラウザでは、キャッシュやクッキーの問題なのか、上手く動かない可能性があります。

もう一つのデモサイトが「講座さがし」です。

WordPressの絞り込み検索のデモサイト

講座の検索や予約ができるサイトをイメージしています。

日付、カテゴリー、フリーワードで検索ができて、検索結果の件数が多い場合など必要に応じてさらに絞り込み検索ができます。

検索結果は、登録日や開催日、値段などによって並び替えができます。また、検索結果の件数と現在のページ番号を表示しています。

他には、「Recruit Company」という仮の求人サイトも作ってみました。

WordPressの絞り込み検索のデモサイト

特徴としては、検索条件にチェックを入れた段階で検索結果の件数が表示されるため、「検索ボタンを押してから検索結果がなかった」というケースが減ります。

絞り込み検索を作る

作成する絞り込み検索のイメージ

まず最初に、どのような絞り込み検索を作るのか、ゴールを紹介します。

WordPressの絞り込み検索

この記事では、上のような不動産の物件を検索する機能をサンプルとして作っていきます。デザインなど細かい部分は適当なので、自由に変えてください。

WordPressの絞り込み検索(検索条件を選択)

「東京にある物件」や「高級な部屋」というように、興味のある条件にチェックを入れて検索ボタンをクリックします。

すると、該当する物件の写真と物件名が表示されて、それをクリックすると物件の詳細ページに飛ぶようにします。

細かい検索の動きは以下の通りです。

  • 最初に表示したときは全ての物件を表示する
  • エリアと特徴が未選択の場合、絞り込みをしない
  • エリアと特徴のそれぞれの選択は、OR条件(または)で絞り込む
    (例)エリアで「埼玉」と「東京」が選択されたら、埼玉または東京の物件を表示
  • エリアと特徴の選択は、AND条件(かつ)で絞り込む
    (例)エリアで「東京」、特徴で「高級」が選択されたら、東京かつ高級な物件を表示
補足
この記事では上のような動きにしていますが、必要に応じて変えてください。例えば、最初に表示したときに物件を表示しない、検索結果の表示件数を絞る、エリアや特徴が未選択のときはエラーを表示するなど。

WordPressの絞り込み検索(検索結果がない)

もしも検索結果がない場合は「該当する物件はありませんでした。」というメッセージを表示します。

検索条件の割り当て

検索条件は、WordPressに標準で用意されているカテゴリーとタグを使います。「エリア」はカテゴリー、「特徴」はタグを割り当てます。

絞り込み検索のプログラム

ここからは、絞り込み検索を作るためのプログラムを紹介します。

テンプレートファイル
<!-- 1. 検索条件の取得と変数の設定 -->
<?php
  $args = array(
    'post_type' => 'post',
    'post_status' => 'publish',
    'posts_per_page' => -1,
    'orderby' => 'date',
    'order' => 'DESC'
  );

  if(!empty($_POST['search_category'])) {
    foreach($_POST['search_category'] as $value) {
      $search_category[] = htmlspecialchars($value, ENT_QUOTES);
    }
    $args += array('category__in' => $search_category);
  }

  if(!empty($_POST['search_tag'])) {
    foreach($_POST['search_tag'] as $value) {
      $search_tag[] = htmlspecialchars($value, ENT_QUOTES);
    }
    $args += array('tag__in' => $search_tag);
  }
?>

<!-- 2. 検索フォームの表示 -->
<div class="search">
<form method="post" action="<?php echo esc_url(home_url() . $_SERVER['REQUEST_URI']); ?>">
<div class="checkbox">

<div class="condition-title">エリア</div>
<div class="condition">
  <?php
    $categories = get_categories(Array('hide_empty' => false));
    foreach($categories as $category):
      $checked = "";
      if(in_array($category->term_id, $search_category)) $checked = " checked";
  ?>
  <label>
  <input type="checkbox" name="search_category[]" value="<?php echo esc_attr($category->term_id); ?>"<?php echo $checked; ?>>
  <?php echo esc_html($category->name); ?>
  </label>
  <?php endforeach; ?>
</div>
		
<div class="condition-title">特徴</div>
<div class="condition">
  <?php
    $tags = get_tags(Array('hide_empty' => false));
    foreach($tags as $tag):
      $checked = "";
      if(in_array($tag->term_id, $search_tag)) $checked = " checked";
  ?>
  <label>
  <input type="checkbox" name="search_tag[]" value="<?php echo esc_attr($tag->term_id); ?>"<?php echo $checked; ?>>
  <?php echo esc_html($tag->name); ?>
  </label>
  <?php endforeach; ?>
</div>	
	
</div>

<input type="submit" value="検索" class="submit-button">

</form>
																														 
<!-- 3. 検索結果の取得と表示 -->
<?php
  $the_query = new WP_Query($args);
  if($the_query->have_posts()) :
?>	
<div class="result">
<?php
  while($the_query->have_posts()) :
    $the_query->the_post();
?>			
<div class="article">
  <a href="<?php the_permalink(); ?>">
  <?php the_post_thumbnail('medium'); ?>
  <div><?php the_title(); ?></div>
  </a>
</div>
<?php endwhile; wp_reset_postdata(); ?>
</div>
<?php else : ?>
<p>該当する物件はありませんでした。</p>
<?php endif; ?>

</div>

少し長いですが、上記が絞り込み検索のプログラムです。もっと良いやり方がある場合は随時変更してください。

また、以下がCSSのサンプルです。ただし、デザインの部分は適当で、デバイスサイズなども考慮されていません。こちらも必要に応じて変えてください。

style.css
.search {
    text-align: center;
}

.search::after {
    content: "";
    display: block;
    clear: both;
}

.search .checkbox {
    width: auto;
    margin: 0 auto;
    display: inline-block;
}

.search .checkbox .condition-title {
    padding: 10px 10px;
    background-color: #828282;
    color: #fff;
}

.search .checkbox .condition {
    padding: 17px;
}

.search .checkbox .condition label {
    margin-right: 10px;
}

.search .submit-button {
    width: 200px;
    background-color: #FF4F50;
    border: none;
    color: #fff;
    display: block;
    margin: 10px auto 50px;
    outline: none;
}

.search .result {
    display: flex;
    align-items: center;
    justify-content: center;
}

.search .result .article {
    float: left;
    margin-right: 20px;
}

プログラムの補足をします。

1. 検索条件の取得と変数の設定

$argsはWP_Queryオブジェクトに渡される変数で、これによってデータベースから取得する記事の条件を定義します。

$_POSTで送信された検索条件を取得します。カテゴリーが選択された場合はcategory__inという抽出条件を$argsに追加し、タグが選択された場合はtag__inという抽出条件を追加します。

2. 検索フォームの表示

formタグを使って検索フォームを表示します。

get_categoriesでカテゴリーの一覧、get_tagsでタグの一覧を取得して、チェックボックスを生成します。hide_emptyがfalseの条件を渡すことで、どの記事にも割り当てられていないカテゴリーやタグも含めて取得しています。

検索結果を表示する際に、in_arrayで選択されたカテゴリーやタグか判定し、その場合はチェックボックスにcheckedを設定します。それによって、検索した後も選択状態を保持しています。

3. 検索結果の取得と表示

検索条件を設定した$argsの変数をWP_Queryオブジェクトに渡して、データベースから検索結果を取得します。

while文で検索結果の数だけループを回して、記事の画像やタイトルを表示します。また、have_postsで検索結果があるか判定を行い、ない場合にはメッセージを表示します。

補足

最初にページを表示したときに検索結果を表示させないためには、hiddenタグを使う方法があります。

テンプレートファイル
<input type="hidden" name="search" value="1">

上のように初回かどうか判定するフラグ用のhiddenタグを追記します。

テンプレートファイル
<?php if(!empty($_POST['search'])) : ?>
  
<!--
  $the_query = new WP_Query($args);
  検索結果を表示するプログラム
-->

<?php endif; ?>

初回はhiddenタグの値がないので、その場合は検索結果を表示するプログラムを除外します。

プログラムを記述する場所

先ほどのプログラムを絞り込み検索を設置したい場所に記述します。

使用しているテーマによって変わりますが、例えば以下のテンプレートに記述します。

テンプレートの例
  • トップページだけに設置する ⇒ index.php、front-page.php
  • 全てのページのフッターに設置する ⇒ footer.php
  • 全てのページのヘッダーに設置する ⇒ header.php
  • 投稿や固定ページに設置する ⇒ 記事の編集画面
  • サイドバーに設置する ⇒ ウィジェット

例えば、検索専用の固定ページを一つ作り、「詳細な検索をしたい方はこちら」という感じでその検索ページに誘導しても良いでしょう。

ヘッダーやフッター、サイドバーなどにプログラムを記述すれば、全てのページで絞り込み検索を使えます。検索ページに毎回戻る必要がないので、検索を何度もして情報を探すようなサイトの場合は、この方法が向いているかもしれません。

複数の場所に絞り込み検索を設置する場合は、同じプログラムを様々な場所に記述することになり、もしも修正があったときに大変です。

そこで、例えば「custom-search.php」といったファイル名で絞り込み検索のテンプレートを作成して、それを呼び出す方法があります。

get_template_partでテンプレートの呼び出し

テンプレートを呼び出すときは、get_template_partにファイル名を指定します。

テンプレートファイル
<?php get_template_part('custom-search'); ?>

投稿や固定ページに絞り込み検索を設置する

投稿や固定ページに絞り込み検索を設置する場合には、「ショートコード」という機能を使います。

なぜなら、投稿や固定ページの編集画面にはPHPのプログラムを記述できないからです。

ショートコードとは何か、ショートコードの作り方などを知らない場合は、以下の記事をお読みください。

まずは、custom-search.phpといった感じで絞り込み検索のテンプレートを作成します。

functions.php
// ショートコードで絞り込み検索を設置する関数
function shortcode_search() {
  ob_start();
  get_template_part('custom-search');
  return ob_get_clean();
}
add_shortcode('search', 'shortcode_search');

次に、functions.phpにadd_shortcodeを使ってショートコードを作成します。

ショートコードで呼び出されるshortcode_searchという関数は、get_template_partで絞り込み検索のテンプレートを呼び出しています。

WordPressの絞り込み検索のショートコード

投稿や固定ページでショートコードを使うときは、絞り込み検索を設置したい場所に[search]を記述するだけです。

WordPressの投稿や固定ページに絞り込み検索を設置

すると、上のように絞り込み検索が設置されているはずです。

補足
絞り込み検索が設置されずにショートコードの文字だけが表示される場合、functions.phpに「add_filter('widget_text', 'do_shortcode');」を記述することを試してみてください。

サイドバーに絞り込み検索を設置する

サイドバーのウィジェットにも標準ではPHPのプログラムを記述できないので、先ほどの手順でショートコードを作成します。

WordPressのウィジェットに絞り込み検索のショートコードを記述

そして、カスタムHTMLのウィジェットを追加して[search]を記述すると、サイドバーに絞り込み検索を設置できます。

WordPressのサイドバーに絞り込み検索を設置

補足
サイドバーは表示スペースが限られているので、サムネイル画像は表示せずに文字のリンクだけにしたり、検索結果の表示件数を絞って詳細な検索は専用ページに誘導したりと、工夫するのがおすすめです。

絞り込み検索を作る(検索条件を追加)

ここからは、先ほどの絞り込み検索をベースに、機能をカスタマイズします。

まずは、検索条件を追加します。例えば、以下のように「価格帯」という検索条件を増やします。

WordPressの絞り込み検索(検索条件を追加)

これまでは、WordPressに標準で用意されているカテゴリーとタグを検索条件として使いました。

カスタムタクソノミーという機能を使うと、カテゴリーやタグと同じような分類を増やすことができるので、それを検索条件として使います。

カスタムタクソノミー(価格帯)

カスタムタクソノミーとは何か、カスタムタクソノミーの作り方などを知らない場合は、以下の記事をお読みください。

カスタムタクソノミーを作成するには、「Custom Post Type UI」というプラグインを使います。

基本的な設定内容は以下の通りです。必要に応じて変更してください。

  • タクソノミースラッグ:price
  • 複数形のラベル:価格帯
  • 単数形のラベル:価格帯
  • 利用する投稿タイプ:投稿
  • 一般公開:True
  • Public Queryable:True
    ※価格帯の一覧ページが不要な場合はFalseを選択
  • 階層:False
  • UIを表示:True
  • メニューに表示する:True
  • ナビゲーションメニューに表示:True
  • クエリー変数:True
  • カスタムクエリー変数文字列:空欄
  • リライト:True
  • カスタムリライトスラッグ:空欄
  • フロントでのリライト:False
  • 階層リライト:False
  • 管理画面でカラムを表示:True
  • REST APIで表示:True
  • クイック編集 / 一括編集パネルに表示:True
  • Metabox callback:空欄

カスタムタクソノミー(価格帯)の管理画面

カスタムタクソノミーを作成すると、管理画面に「価格帯」の分類が追加されます。カテゴリーやタグと同様に、価格帯の名前とスラッグを入力すると項目を作成できます。

カスタムタクソノミー(価格帯)の割り当て

投稿の編集画面を開くと、価格帯を割り当てられるようになっています。

絞り込み検索のプログラム

絞り込み検索のプログラムを以下のように修正します。

テンプレートファイル
<!-- 1. 検索条件の取得と変数の設定 -->
if(!empty($_POST['search_price'])) {
  foreach($_POST['search_price'] as $value) {
    $search_price[] = htmlspecialchars($value, ENT_QUOTES);
  }
  $args += array('tax_query' => array(array(
                   'taxonomy' => 'price',
                   'terms' => $search_price,
                   'field' => 'slug',
                   'operator' => 'IN'
                 )));
}

まずは、「1. 検索条件の取得と変数の設定」の手順に上のプログラムを追記します。

$_POSTで価格帯の検索条件を取得して、tax_queryという抽出条件を$argsに追加します。

テンプレートファイル
<!-- 2. 検索フォームの表示 -->
<div class="condition-title">価格帯</div>
<div class="condition">
  <?php
    $prices = get_terms('price', Array('hide_empty' => false, 'orderby' => 'slug'));
    foreach($prices as $price):
      $checked = "";
      if(in_array($price->slug, $search_price)) $checked = " checked";
  ?>
  <label>
  <input type="checkbox" name="search_price[]" value="<?php echo esc_attr($price->slug); ?>"<?php echo $checked; ?>>
  <?php echo esc_html($price->name); ?>
  </label>
  <?php endforeach; ?>
</div>

次に、「2. 検索フォームの表示」の手順に上のプログラムを追記します。

get_termsで価格帯の一覧を取得して、チェックボックスを生成します。orderbyは並び替えの条件なので、不要なら削除してください。

絞り込み検索を作る(カスタム投稿タイプ)

これまでは、WordPressに標準で用意されている「投稿」を絞り込み検索しました。

次は、カスタム投稿タイプの記事を絞り込み検索するようにカスタマイズします。

カスタム投稿タイプ(お知らせ)

例えば、投稿はブログとして記事を書いているときに、カスタム投稿タイプでお知らせの記事を書いて、年やジャンルで絞り込み検索するケースです。

今までのやり方と組み合わせれば、投稿とカスタム投稿タイプのそれぞれで絞り込み検索を設置することもできます。

カスタム投稿タイプとは何か、カスタム投稿タイプの作り方などを知らない場合は、以下の記事をお読みください。

WordPressの絞り込み検索(カスタム投稿タイプ)

サンプルとしては、これまでと同様に上のような物件を検索する機能を作ります。

「不動産(house)」というカスタム投稿タイプを作り、「エリア(area)」と「価格帯(price)」というカスタムタクソノミーで絞り込み検索を行います。

絞り込み検索のプログラム

テンプレートファイル
<!-- 1. 検索条件の取得と変数の設定 -->
<?php
  $args = array(
    'post_type' => 'house',
    'post_status' => 'publish',
    'posts_per_page' => -1,
    'orderby' => 'date',
    'order' => 'DESC'
  );

  if(!empty($_POST['search_area'])) {
    foreach($_POST['search_area'] as $value) {
      $search_area[] = htmlspecialchars($value, ENT_QUOTES);
    }
    $tax_query_args[] = array(
                           'taxonomy' => 'area',
                           'terms' => $search_area,
                           'field' => 'slug',
                           'operator' => 'IN'
                        );
  }

  if(!empty($_POST['search_price'])) {
    foreach($_POST['search_price'] as $value) {
      $search_price[] = htmlspecialchars($value, ENT_QUOTES);
    }

    $tax_query_args[] = array(
                           'taxonomy' => 'price',
                           'terms' => $search_price,
                           'field' => 'slug',
                           'operator' => 'IN'
                        );
  }

  if(!empty($_POST['search_area']) || !empty($_POST['search_price'])) {
    $args += array('tax_query' => array($tax_query_args));
  }
?>

まずは、「1. 検索条件の取得と変数の設定」の手順を上のプログラムで丸ごと全て置き換えます。

やっていることは、今までのプログラムとほとんど変わりません。主な違いは、まずpost_typeでカスタム投稿タイプのスラッグ(house)を指定するところです。

そして、$_POSTで検索条件を取得して、それがある場合はtax_queryという抽出条件を$argsに追加します。

テンプレートファイル
<!-- 2. 検索フォームの表示 -->
<div class="condition-title">エリア</div>
<div class="condition">
  <?php
    $areas = get_terms('area', Array('hide_empty' => false));
    foreach($areas as $area):
      $checked = "";
      if(in_array($area->slug, $search_area)) $checked = " checked";
  ?>
  <label>
  <input type="checkbox" name="search_area[]" value="<?php echo esc_attr($area->slug); ?>"<?php echo $checked; ?>>
  <?php echo esc_html($area->name); ?>
  </label>
  <?php endforeach; ?>
</div>

<div class="condition-title">価格帯</div>
<div class="condition">
  <?php
    $prices = get_terms('price', Array('hide_empty' => false, 'orderby' => 'slug'));
    foreach($prices as $price):
      $checked = "";
      if(in_array($price->slug, $search_price)) $checked = " checked";
  ?>
  <label>
  <input type="checkbox" name="search_price[]" value="<?php echo esc_attr($price->slug); ?>"<?php echo $checked; ?>>
  <?php echo esc_html($price->name); ?>
  </label>
  <?php endforeach; ?>
</div>

次に、「2. 検索フォームの表示」の手順で検索条件を表示している部分を上のプログラムで置き換えます。formタグや検索ボタンなどの部分はそのままで良いです。

エリアも価格帯もカスタムタクソノミーなので、get_termsを使って一覧を取得して、チェックボックスを生成します。

絞り込み検索を作る(ページ送り)

ここでは、絞り込み検索の結果にページャーを設置する方法を紹介します。

自作の絞り込み検索にページャーを設置

絞り込み検索のプログラム

テンプレートファイル
<!-- 1. 検索条件の取得と変数の設定 -->
<?php
  // ページ番号を取得
  $paged = get_query_var('paged') ? get_query_var('paged') : 1;
  $args = array(
    'paged' => $paged, // ページ番号を設定
    'post_type' => 'post',
    'post_status' => 'publish',
    'posts_per_page' => 2, // 一つのページに表示する件数を設定
    'orderby' => 'date',
    'order' => 'DESC'
  );

  // POSTをGETに変更
  if(!empty($_GET['search_category'])) {
    foreach($_GET['search_category'] as $value) {
      $search_category[] = htmlspecialchars($value, ENT_QUOTES);
    }
    $args += array('category__in' => $search_category);
  }

  if(!empty($_GET['search_tag'])) {
    foreach($_GET['search_tag'] as $value) {
      $search_tag[] = htmlspecialchars($value, ENT_QUOTES);
    }
    $args += array('tag__in' => $search_tag);
  }
?>

まずは、「1. 検索条件の取得と変数の設定」の手順を上のように修正します。

get_query_varで現在のページ番号を取得しています。初めてページを表示したときはページ番号が取得できないので、「1」を設定しています。

そして、$argsの抽出条件に現在のページ番号(paged)と一つのページに表示する件数(posts_per_page)を設定します。

これまではPOSTで検索していましたが、ページ送りをする場合はGETの方がやりやすいと思います。そのため、POSTと書いていたところをGETに変えます。

テンプレートファイル
<!-- 2. 検索フォームの表示 -->
<form method="get" action="<?php echo esc_url(get_the_permalink()); ?>">

次に、「2. 検索フォームの表示」の手順を上のように修正します。

formタグのmethodをGETに変更して、actionは今までの設定だとページ番号付きのURLが入ってしまうので、変えています。

テンプレートファイル
<!-- 3. 検索結果の取得と表示 -->
<?php endwhile; wp_reset_postdata(); ?>
</div>
<?php
    // ページャーを設置
    echo paginate_links(array(
        'total' => $the_query->max_num_pages,
        'current' => $paged,
        'type' => 'list',
    )); 
?>
<?php else : ?>
<p>該当する物件はありませんでした。</p>
<?php endif; ?>

最後に、「3. 検索結果の取得と表示」の手順を上のように修正します。場所が分かるように他のプログラムも書いていますが、paginate_linksの部分を追記するだけです。

ページャーを設置する方法は色々あります。自作のプログラムはインターネットで検索すれば見つかりますし、「WP-PageNavi」というプラグインもあります。

どのやり方でも良いですが、ここではWordPressの標準の関数であるpaginate_linksを使っています。

他にもパラメータは設定できますし、ページャーのデザインも適当です。必要に応じて変更してください。

補足

ページャーを設置できるWordPressの標準の関数には、the_posts_paginationというものもあります。

しかし、こちらは内部で$GLOBALS['wp_query']->max_num_pagesというプログラムが書かれており、メインクエリでないとページャーが表示されません。

テンプレートファイル
$GLOBALS['wp_query']->max_num_pages = $the_query->max_num_pages;

今回のようにサブクエリでページャーを表示するには、上のように少し強引にメインクエリの変数を置き換える必要があります。

絞り込み検索を作る(Ajax)

最後に、Ajax(エイジャックス)を使って絞り込み検索するようにカスタマイズします。

Ajaxとは、JavaScript(jQuery)でサーバーと非同期通信を行う技術です。ページ全体ではなく、部分的にデータを書き換えることができます。

例えば、絞り込み検索であれば、気になる情報が見つかるまで検索条件を変えて何度も検索を試すと思います。

通常では、検索ボタンを押すたびにブラウザがリロードされます。

一方でAjaxを使うと、ヘッダーやフッターなどはそのままで、検索の部分だけをサーバーから取得した情報で再表示できます。

Ajaxとは

それによって、検索結果が表示されるまでの時間を短縮できて、ユーザビリティが向上するというメリットがあります。

WordPressの絞り込み検索(Ajax)

サンプルとしては、これまでと同様に上のような物件を検索する機能を作ります。投稿の記事を検索の対象にしていますが、カスタム投稿タイプでも同様です。

絞り込み検索のプログラム

テンプレートファイル
<!-- (追記1)Ajaxの結果を表示する領域を設定 -->
<div id="search-result">
<div class="search">
<form method="post" action="<?php echo esc_url(home_url() . $_SERVER['REQUEST_URI']); ?>">
<div class="checkbox">

<div class="condition-title">エリア</div>
<div class="condition">
  <?php
    $categories = get_categories(Array('hide_empty' => false));
    foreach($categories as $category):
      $checked = "";
      if(in_array($category->term_id, $search_category)) $checked = " checked";
  ?>
  <label>
  <input type="checkbox" name="search_category[]" value="<?php echo esc_attr($category->term_id); ?>"<?php echo $checked; ?>>
  <?php echo esc_html($category->name); ?>
  </label>
  <?php endforeach; ?>
</div>
		
<div class="condition-title">特徴</div>
<div class="condition">
  <?php
    $tags = get_tags(Array('hide_empty' => false));
    foreach($tags as $tag):
      $checked = "";
      if(in_array($tag->term_id, $search_tag)) $checked = " checked";
  ?>
  <label>
  <input type="checkbox" name="search_tag[]" value="<?php echo esc_attr($tag->term_id); ?>"<?php echo $checked; ?>>
  <?php echo esc_html($tag->name); ?>
  </label>
  <?php endforeach; ?>
</div>
	
</div>

<input type="submit" value="検索" class="submit-button">

<!-- (追記2)nonceのhiddenタグを生成 -->
<?php wp_nonce_field('my-ajax-nonce', 'nonce'); ?>
</form>

<?php
  $the_query = new WP_Query($args);
  if($the_query->have_posts()) :
?>	
<div class="result">
<?php
  while($the_query->have_posts()) :
    $the_query->the_post();
?>			
<div class="article">
  <a href="<?php the_permalink(); ?>">
  <?php the_post_thumbnail('medium'); ?>
  <div><?php the_title(); ?></div>
  </a>
</div>
<?php endwhile; wp_reset_postdata(); ?>
</div>
<?php else : ?>
<p>該当する物件はありませんでした。</p>
<?php endif; ?>

</div>

<!-- (追記3)Ajaxで使う変数の設定とスクリプトを読み込み -->
<script>
    var ajaxurl = '<?php echo esc_url(admin_url('admin-ajax.php')); ?>';
</script>
<script src="<?php echo esc_url(get_stylesheet_directory_uri() . '/js/main.js'); ?>"></script>

</div>

「1. 検索条件の取得と変数の設定」の手順に関しては今までと全く同じなので省略しています。それ以外の部分を上のプログラムで丸ごと全て置き換えます。

変更点は以下の通りです。

(追記1)Ajaxの結果を表示する領域を設定

「1. 検索条件の取得と変数の設定」の手順を除いた全体を「search-result」というID属性を付けたdivタグで囲います。

テンプレートファイル
<div id="search-result">
<!-- 「1. 検索条件の取得と変数の設定」の手順を除いた部分 -->
</div>

この部分が、検索ボタンをクリックしたときにAjaxによって書き換えられます。

(追記2)nonceのhiddenタグを生成

formの終了タグの前に、wp_nonce_fieldの処理を一行追記します。

wp_nonce_fieldは、nonce(ノンス)と呼ばれる乱数をhiddenタグとして生成する関数です。関数を実行すると、以下のようなタグが生成されます。

wp_nonce_field
<input type="hidden" id="nonce" name="nonce" value="XXXXXXXXX(nonceの値)">

nonceはクロスサイトリクエストフォージェリ(CSRF)などのセキュリティ対策に使われます。詳細は以下の記事をお読みください。

参考 CSRFの対策JPCERT
補足
実際に使うときは、「my-ajax-nonce」よりもランダムな英数字の方がセキュリティは少し高いかなと思います。

(追記3)Ajaxで使う変数の設定とスクリプトを読み込み

Ajaxで使う2種類のscriptタグを追記します。

一つ目は、ajaxurlという変数にAjaxを行うURLを定義しています。

二つ目は、Ajaxで検索結果を取得する処理を記述したJavaScriptの外部ファイルを読み込んでいます。「/js/main.js」というパスとファイル名にしていますが、ご自身の内容に置き換えてください。

補足
一般的に、JavaScriptの外部ファイルを読み込むときは、以下のようにfunctions.phpでwp_enqueue_scriptを使うことが推奨されています。

functions.php
function my_theme_enqueue_scripts() { 
    wp_enqueue_script('main-js', get_stylesheet_directory_uri() . '/js/main.js', array(), false, true);
}
add_action('wp_enqueue_scripts', 'my_theme_enqueue_scripts');

wp_enqueue_scriptを使うと、スクリプトを一元管理できたり、依存するスクリプトがある場合に読み込み順序を変えたりできます。

ただし、この方法を使うと、全てのページでスクリプトが読み込まれます。

例えば、専用の検索ページを用意しており、しかもmain.jsに絞り込み検索の処理しか記述されていない場合、検索ページ以外では無駄な読み込みが発生してパフォーマンスが悪化します。

そのため、wp_enqueue_scriptを使う場合にも、必要に応じて分岐を入れることを検討してください。

main.js
jQuery(function($){
    function customSearch(){
        // 1. フォームのデータを生成
        var form = $('#search-result form').get()[0];
        var formData = new FormData(form);
        formData.append('action', 'custom_search');

        // 2. Ajaxを行う
        $.ajax({
          type: 'POST',
          url: ajaxurl,
          data: formData,
          processData: false,
          contentType: false,
          success: function(data){
            $('#search-result').prop('outerHTML', data);
            $('.submit-button').attr('type', 'button');
          }
        });
        return false;
    };

    // 3. クリックイベントの設定
    $('.submit-button').attr('type', 'button');
    $(document).on('click', '.submit-button', function(){
        customSearch();
    });
});

上記がAjaxを行うJavaScriptのプログラムです。customSearchという自作の関数でAjaxを行い、検索結果を表示しています。

以下にプログラムの補足をします。

1. フォームのデータを生成

FormDataオブジェクトを作成して、「action」というキーに「custom_search」という値を設定しています。custom_searchはAjaxで検索結果を表示する自作の関数で、後の手順でfunctions.phpに処理を記述します。

2. Ajaxを行う

Ajaxを行うURLや送信するフォームのデータなどのパラメーターを設定して、Ajaxを行います。

処理が成功したときは、dataという変数で検索部分のHTMLを受け取って、「search-result」というID属性を付けたdivタグを丸ごと置き換えています。

補足

検索ボタンのtype属性をbuttonに変えている理由は、submitのままだとAjaxではなく通常の検索処理が行われてしまうからです。

type属性を最初からbuttonにしても良いのですが、そうするとJavaScriptが有効化されていない環境では検索できません。

3. クリックイベントの設定

検索ボタンをクリックしたときにcustomSearchが実行されるように、クリックイベントを設定しています。

補足
jQueryにはclick()という関数がありますが、使っていません。これを使うと、2回目に検索ボタンをクリックしたときに効きません。
functions.php
// Ajaxで検索結果を表示する関数
function custom_search() {
    $nonce = $_REQUEST['nonce'];
    if(wp_verify_nonce($nonce, 'my-ajax-nonce')) {
        get_template_part('custom-search');
    }
    die();
}
add_action('wp_ajax_custom_search', 'custom_search');
add_action('wp_ajax_nopriv_custom_search', 'custom_search');

上記が検索ボタンをクリックしたときにAjaxで呼ばれる自作の関数です。$_REQUESTでnonceを取得して、wp_verify_nonceで検証しています。

nonceがなかったり、値が違う場合には、不正なリクエストとして処理を中断します。検証が成功したら、get_template_partで絞り込み検索のテンプレートを呼び出します。

なお、wp_verify_nonceの第2引数は、wp_nonce_fieldで設定したアクションの名前と同じにしてください。

作成した関数は「wp_ajax_{関数名}」と「wp_ajax_nopriv_{関数名}」というアクション名で追加します。後者を削除すると、WordPressをログアウトした状態では関数を実行できなくなります。

検索ボタンをクリックせずに検索を行う

おまけとして、検索条件のチェックボックスを選択した段階で絞り込みを行うようにカスタマイズします。

検索ボタンをクリックする必要がないので、場合によっては利便性が向上します。

WordPressの絞り込み検索(検索ボタンなし)

補足
この方法の場合はJavaScriptが有効化されている必要があります。
main.js
$(document).on('click', 'input[name="search_category[]"], input[name="search_tag[]"]', function(){
    customSearch();
});

主な修正点は、JavaScriptのプログラムの中で検索ボタンに対してクリックイベントを設定していたところを、上のようにチェックボックスに変えます。

後は、テンプレートファイルから検索ボタンを削除するだけです。

まとめ

この記事では、WordPressで絞り込み検索を作る方法を紹介しました。

ページ数の多い大規模なサイトでは、絞り込み検索を設置することで使い勝手が大きく向上する可能性があります。

最初は難しく感じるかもしれませんが、ぜひ挑戦してみてください。

なお、この記事の正確性は保証しません。全て自己責任で参考にしてください。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

CAPTCHA