WordPressに絞り込み検索を実装する【プラグイン無し】

WordPressに絞り込み検索を実装する【プラグイン無し】

プラグインを使用せずに、フリーワード、カテゴリー、タグで絞り込み検索を実装する方法を紹介します。
絞り込み検索は”WP_Query”のパラメーター、”tax_query”を活用するのがポイントです 。

【前準備】タクソノミー(カテゴリー)名を検索できるようにしておく

【前準備】は不要かも…!? ※調査中

WordPress5からタクソノミーも検索対象になっているような気がするようなしないような… 現在調査中です。(2019年11月3日現在)
また追記します。(スミマセン)

WordPressデフォルトではカテゴリー名はフリーワードで検索できず…事前準備として対策しておきます。 手っ取り早くプラグインを使用する方法と、functions.phpに記述する方法、両方書いておきますね。

方法1 プラグインを使用する

“WP Extended Search”プラグインを使用します。

方法2 function.phpに記述する

SQL文を使用してカテゴリー名を検索しています。

function my_custom_search($search, $wp_query) {
	global $wpdb;
	
	if (!$wp_query->is_search)
		return $search;
	if (!isset($wp_query->query_vars))
		return $search;

	$search_words = explode(' ', isset($wp_query->query_vars['s']) ? $wp_query->query_vars['s'] : '');

	if ( count($search_words) > 0 ) {
			$search = '';

		    foreach ( $search_words as $word ) {
             if ( !empty($word) ) {
				 
				$search_word = '%' . esc_sql( $word ) . '%';
				$search .= " AND (
					{$wpdb->posts}.post_title LIKE '{$search_word}'
					OR {$wpdb->posts}.post_content LIKE '{$search_word}'
					OR {$wpdb->posts}.ID IN (
						SELECT distinct tr.object_id
						FROM {$wpdb->term_relationships} AS tr
						INNER JOIN {$wpdb->term_taxonomy} AS tt ON tr.term_taxonomy_id = tt.term_taxonomy_id
						INNER JOIN {$wpdb->terms} AS t ON tt.term_id = t.term_id
						WHERE t.name LIKE '{$search_word}'
					OR t.slug LIKE '{$search_word}'
					OR tt.description LIKE '{$search_word}'
						)
					OR {$wpdb->posts}.ID IN (
						SELECT distinct post_id
						FROM {$wpdb->postmeta}
						WHERE meta_value LIKE '{$search_word}'
						)
					) ";
				}
			}			

	}

	return $search;
}
add_filter('posts_search','my_custom_search', 10, 2);

とりあえずコード全部

「searchform.php」が検索フォーム、「search.php」が検索結果を表示するテンプレートになります。「search.php」の下部でget_search_form() 関数で「searchform.php」を読み込んでおり、結果ページでも検索フォームを表示して再検索できるようにしています。

searchform.php
<form role="search" method="get" id="searchform" action="<?php echo esc_url(home_url('/')); ?>">

<h2>カテゴリー</h2>
<?php
$category_args = array(
	'orderby' => 'name',
	'order' => 'ASC',
);
$categories = get_terms( 'category', $category_args );
foreach($categories as $category) :
?>
<label><input type="checkbox" name="get_cats[]" value="<?php echo $category->slug; ?>"><?php echo $category->name; ?></label>
<?php endforeach; ?>

<h2>タグ</h2>
<?php
$post_tag_args = array(
	'orderby' => 'name',
	'order' => 'ASC',
);
$post_tags = get_terms( 'post_tag', $post_tag_args );
foreach($post_tags as $post_tag) :
?>
<label><input type="checkbox" name="get_tags[]" value="<?php echo $post_tag->slug; ?>"><?php echo $post_tag->name; ?></label>
<?php endforeach; ?>

<h2><?php _x( 'Search for:', 'label' ); ?>キーワード</h2>
<input type="text" value="<?php echo get_search_query(); ?>" name="s" id="s" placeholder="キーワードを入力してください" />


<input type="submit" value="検索" />
</form>

search.php
<?php get_header(); ?>

<?php
$s = $_GET['s'];
$get_cats = $_GET['get_cats'];
$get_tags = $_GET['get_tags'];

if($get_cats) {
	$tax_ary[] = array(
		'taxonomy' => 'category',
		'field' => 'slug',
		'terms' => $get_cats,
		'operator' => 'IN', //ANDかIN
	);
}
if($get_tags) {
	$tax_ary[] = array(
		'taxonomy' => 'post_tag',
		'field' => 'slug',
		'terms' => $get_tags,
		'operator' => 'IN', //ANDかIN
	);
}
?>
<?php if (!($s || $get_cats || $get_tags)): ?>
	<p>検索条件を指定してください</p>
	<?php get_search_form(); ?>
<?php else: ?>

<h1>検索結果</h1>
<?php
if(is_array($get_cats)) {
	echo '<p>カテゴリー:';
	foreach ($get_cats as $val) {
		$p_term = get_term_by('slug', $val, 'category');
		echo $p_term->name;
		if ($val !== end($get_cats)) {
			echo ', ';
		}
	}
	echo '</p>';
} ?>
<?php
if(is_array($get_tags)) {
	echo '<p>タグ:';
	foreach ($get_tags as $val) {
		$s_term = get_term_by('slug', $val, 'post_tag');
		echo $s_term->name;
		if ($val !== end($get_tags)) {
			echo ', ';
		}
	}
	echo '</p>';
} ?>
<?php
if($s) { echo '<p>キーワード:'.$s.'</p>'; } ?>

<?php
	$my_query = new WP_Query( array(
		'paged' => get_query_var('paged'),
		'post_type' => 'post',
		'tax_query' => $tax_ary,
		'relation' => 'AND', //ANDかOR
		's' => $s,
)); ?>
<?php if($my_query->have_posts() ) : ?>
<ul>
<?php while( $my_query->have_posts()) : $my_query->the_post(); ?>
<li><a href="<?php the_permalink() ?>"><?php the_title(); ?></a>
</li>
<?php endwhile; ?>
</ul>
<?php else: ?>
<p>結果が見つかりませんでした。</p>
<?php endif; ?>
<?php get_search_form(); ?>
<?php endif; ?>

<?php get_sidebar(); ?>
<?php get_footer(); ?>

searchform.phpの解説

カテゴリー、タグの情報をget_terms関数で取得、foreachループでformのチェックボックスとして 一覧出力しています。
キーワード欄は通常の検索と同じ記述です。

カスタムタクソノミーやカスタム投稿の場合は?

get_terms( $taxonomies, $args )の$taxonomiesの部分にカスタムタクソノミー名を指定します。

$categories = get_terms( 'category', $category_args );
↓↓↓
$taxonomies = get_terms( 'my_taxonomy', $taxonomy_args );

また、検索範囲をカスタム投稿に限定したい場合はformタグのactionのURIにカスタム投稿名(post_type)を指定します。

<form role="search" ... action="<?php echo esc_url(home_url('/')); ?>my_post/">

search.phpの解説

まず冒頭の$_GETで検索フォームでチェックされた項目及びフリーワードを取得しています。

$s = $_GET['s'];
$get_cats = $_GET['get_cats'];
$get_tags = $_GET['get_tags'];

もし何もチェックが無く、フリーワードも入力されていない場合は「検索条件を指定してください」というメッセージを出力します。
入力があれば、検索結果を表示します。

<?php if (!($s || $get_cats || $get_tags)): ?>

	<p>検索条件を指定してください</p>
	<?php get_search_form(); ?>
	
<?php else: ?>

<h1>検索結果</h1>
//~省略~

<?php endif; ?>

チェックした項目とフリーワードを表示します。
この部分は無くてもいいのですが、検索条件を表示してあげる方が親切だと思います。

<h1>検索結果</h1>
<?php
if(is_array($get_cats)) {
	echo '<p>カテゴリー:';
	foreach ($get_cats as $val) {
		$p_term = get_term_by('slug', $val, 'category');
		echo $p_term->name;
		if ($val !== end($get_cats)) {
			echo ', ';
		}
	}
	echo '</p>';
} ?>
<?php
if(is_array($get_tags)) {
	echo '<p>タグ:';
	foreach ($get_tags as $val) {
		$s_term = get_term_by('slug', $val, 'post_tag');
		echo $s_term->name;
		if ($val !== end($get_tags)) {
			echo ', ';
		}
	}
	echo '</p>';
} ?>
<?php
if($s) { echo '<p>キーワード:'.$s.'</p>'; } ?>

WP_Queryを使って検索結果を取得します。
‘tax_query’パラメータ―には、チェックしたカテゴリーとタグを指定します。
冒頭の$_GETで取得しましたよね。
パラメータ―’s’はフリーワードです。
後はループで検索結果の投稿一覧を出力しています。

カスタムタクソノミーやカスタム投稿の場合は?

カスタムタクソノミーの場合は’tax_query’の’taxonomy’パラメータ―の部分にカスタムタクソノミー名を指定します。

$tax_ary[] = array(
	'taxonomy' => 'my_taxonomy', ...
);

AND / OR検索

カテゴリーやタグ同士の場合は、’tax_query’の’operator’にANDかIN(OR)で指定、カテゴリーとタグ間の場合はWP_Queryの’relation’にANDかORを指定します。
ソースコードにコメントを付けていますので確認してみてくださいね。

この記事をシェア

Categories

Profile

兵庫県神戸市でWEB/DTPまわりのフリーランスをしています。
当ブログは主に業務で出会った諸々の備忘録です。

イラストスイッチ