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

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

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

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

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

なお、プログラミングが苦手な方は「VK Filter Search」というプラグインがおすすめです。

VK Filter Search

このプラグインを使うと、上記のような絞り込み検索の機能を一瞬で作成できます。驚くべきことにブロックエディターのブロックでできているため、HTMLやPHPなどの専門知識は不要です。

このプラグインは「Lightning」というテーマで有名な「Vektor」が開発しています。Lightningも非常に素晴らしいテーマですが、それと同様にVK Filter Searchの使いやすさも素晴らしいです。

目次

絞り込み検索を作る

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

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

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>

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

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

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といった感じで絞り込み検索のテンプレートを作成します。

// ショートコードで絞り込み検索を設置する関数
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
  • 一般公開クエリー可: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タグとして生成する関数です。関数を実行すると、以下のようなタグが生成されます。

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

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

補足

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

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

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

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

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

補足

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

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を使う場合にも、必要に応じて分岐を入れることを検討してください。

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回目に検索ボタンをクリックしたときに効きません。

// 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が有効化されている必要があります。

$(document).on('click', 'input[name="search_category[]"], input[name="search_tag[]"]', function(){
    customSearch();
});

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

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

まとめ

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

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

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

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

コメント(現在、質問は受け付けていません)

コメント一覧 (19件)

  • はじめまして。連絡フォームが見つからずコメントにて失礼いたします。
    現在、求人サイトを作成したく色々検索していたところこのページに辿りつきました。
    求人サイトを作成したいのですが、依頼等は可能でしょうか?

    ご連絡いただけますと大変うれしいです。

    • 大変申し訳ありませんが、今のところ求人サイトの制作代行はしておりません。

  • コメント失礼いたします。
    まさに、不動産サイトを制作しておりまして
    こちら大変参考になりました。

    1点ご質問がございます。
    サイドバーに設置した時に、絞りこみ条件だけにして検索結果(検索ボタンクリックで)を固定ページなどに一覧で出したいのですが、「3. 検索結果の取得と表示」のみを固定ページに記載しても動作いたしましませんでした。

    こちらお手数ですがお分かりになりましたらご教示願いますでしょうか?

    • ちょっと分かりませんが、少なくとも「1. 検索条件の取得と変数の設定」のような処理を書かないと、検索条件による絞り込みはされないと思います。

  • コメント失礼いたします。
    WP及びPHP初心者にもかかわらず、こちらの記事を参考にさせていただき、絞り込み検索を作成することができました。
    ありがとうございます。

    1点お伺いしたい事があります。
    恐らく、にゃんまるさんと同じ質問内容なのかもしれません。

    絞り込み検索をサイドバーに設置したのですが、検索結果が検索フォームの下部に表示されます。
    理想は、検索フォームはサイドバー、検索結果はメインコンテンツに表示したいです。

    もし可能なようであればお教えいただけないでしょうか。
    ご指導のほど、よろしくお願いいたします。

    • 初心者で絞り込み検索を作成するのはとてもすごいと思います。

      申し訳ありませんが、絞り込み検索の記事に関して追記・編集する時間がありません。

      余裕ができたらいつか追記するかもしれませんが、期待しないでください。

  • はじめまして。コメント失礼いたします。
    WordPressのポートフォリオサイトを作成中で本サイトを閲覧させていただき絞り込み検索を実装することが叶いました。ありがとうございました。
    当該コードについてご質問失礼します
    「第4項ページネーション追加」にて $argsのパラメータに'posts_per_page' => 10,として設定し10件表示するようにした上で、条件の絞り方によりページネーションがうまく機能しませんでした。
    「絞り込み検索:投稿数12件の絞り方を行い→2ページ目へ→投稿数10件以下の条件を選択し表示する」と記事が表示されなくなります。
    ページが2ページ目になっているため1ページ目でしかない投稿は表示されなくなってしまいました。

    $argsのtax_queryもしくは$tax_query_argsのどちらでもいいので、「前回のパラメータと違っていたら」という条件分岐もしくは、
    「新規条件検索」で分岐できれば$pegadを書き換える事でうまくいきそうなのですが、良い方法があればご教授いただきたいです。
    もし可能でしたらご回答いただければ幸いです。
    宜しくおねがいします。

    • すみません、ちょっと試せていないのですが、「4. 絞り込み検索を作る(ページ送り)」のformタグの変更部分は同じになっていますか?

      • コメント返信ありがとうございます。
        フォームタグの変更ですが、すべてをGET属性に変更確認済みでありますが、
        してされたフォームタグではチェックされた記事スラッグへのパーマリンクとなってしまって、うまく動作しませんでした。
        $ページド を渡しても現在のページになるだけなので解決には至りません。

        • この記事のコードを使って簡単に試した感じでは、私の環境では再現しませんでした。

          状況がよく分からないのですが、固定ページに検索フォームがあるイメージですか?

          2ページ目の検索結果を表示したときに、formタグのaction属性にページ番号は入っていますか?

          私の環境では、固定ページのURLが入っているだけで、ページ番号は含まれていないと思います。

  • コメント返信ありがとうございます。
    状況としましてはカスタム投稿タイプのアーカイブページ(archve-blog.php)にて「3.絞り込み検索を作る(カスタム投稿タイプ)」の項目と同じ記述(GET分岐変更済み)です。
    なので検索フォームのすぐ下に記事が並ぶ形です。

    2ページ目の検索結果を表示したときに、formタグのaction属性にページ番号は入っていますか?
    >はい。2ページ目のURLの例です。
    「ドメイン/blogs/page/2/?search_cat%5B0%5D=php」と、このように番号が入ってしまいます。
    action属性のget_the_permalink()の引数は指定しなくても良いですか?

    やはりフォームタグのaction属性に「page/2/」が入ってしまうことが原因ですね。

    • ちょっと試していませんが、action属性のコードに「action="/blogs"」みたいな感じで、アーカイブページのURLを直接書くとどうなりますか?

      • ありがとうございました!! 上記の方法で解決に至りました!!

        直接URLを記述することで問題なく動作しました。
        「投稿数10件以下のページを検索」した際には「page/2/」が消えました。

        ちなみに、同じ要領でサーバー変数から取得したものでもうまく動作しました。
        ※例
        $host = $_サーバー['HTTP_HOST'];
        $url = rtrim(dirname($_サーバー['PHP_SELF']),'/\\');
        esc_url($host.$url.'/blogs/')

        今回相当悩まされましたが勉強できる素晴らしい記事に出会えたことを光栄に思います。
        ありがとうございました。

  • ちょうど探していたコードに出会えました!ありがとうございます。
    ただ、1箇所だけうまくいかなくて質問させてください…!

    ajaxの処理を入れるとどうしても
    wp-admin/admin-ajax.phpで400エラーが出て
    ajaxが動かないんです。

    すごくざっくりで申し訳ないのですが、
    ワードプレス特有の記述が足りないのか何かわかりますでしょうか?

    ボタン押下でページをリロードするところまではうまくいってました!

    • ちょっとこの情報だけではよく分かりませんが、
      例えば、wp_nonce_fieldとwp_verify_nonceの部分は記事と同じになっていますか?

  • コメント失礼いたします。
    1番のコードを参考にさせていただき、絞り込み検索を作成することができました。
    とてもわかりやすく解説していただきありがとうございます。

    1番ではカテゴリの絞り込みをOR条件で行っていますが、AND条件にする場合
    どの部分のコードを変更すればいいかわからない状況です。
    ヒントなどご教示いただけますと幸いです。

    • 試していませんが、「category__in」の部分を「category__and」に変えるとAND条件になりませんか?

      $args += array( 'category__and' => $search_category );

      間違っていたらすみません。

コメントする

CAPTCHA


目次
閉じる