Posted on

Category filter for search results pages

Sometimes it’s nice to have a category filter on the search results pages: a simple dropdown where you can choose the category you want to show. It’s easy to create one using wp_dropdown_categories(), but on a search results page that’s slightly problematic, as it’ll include all categories, not just those included in the search results.

So, here’s a two-part function that fixes that. First, we need a filter that processes the search results and gets a list of categories in the results. This filter runs very late on the relevanssi_hits_filter hook, so that it runs after other filters on the same hook:

add_filter('relevanssi_hits_filter', 'rlv_gather_categories', 99);
function rlv_gather_categories($hits) {
	global $rlv_categories_present;
	$rlv_categories_present = array();
	foreach ( $hits[0] as $hit ) {
		$terms = get_the_terms( $hit->ID, 'category' );
		foreach ( $terms as $term ) {
			$rlv_categories_present[ $term->term_id ] = $term->name;
		}
	}
 
	asort( $rlv_categories_present );
	return $hits;
}

If you want this to use WooCommerce product categories, replace the category in the get_the_terms() call with product_cat, like this:

		$terms = get_the_terms( $hit->ID, 'product_cat' );

Now that’s in place (put both of these functions to theme functions.php, or some other suitable place), we can create the function that displays the dropdown. It’s a simple dropdown that lists the categories in alphabetical order (that comes from the asort() in the first function, actually) and includes a bit of JavaScript that adds a cat parameter with the correct value to the current URL and reloads the page.

If a category parameter is already in place, there’s instead a link that removes all category filters.

function rlv_category_dropdown() {
	global $rlv_categories_present, $wp_query;
 
	if (!empty($wp_query->query_vars['cat'])) {
		$url = esc_url(remove_query_arg('cat'));
		echo "<p><a href='$url'>Remove category filter</a>.</p>";
	}
	else {
		$select = "<select id='rlv_cat' name='rlv_cat'>
		<option value=''>Choose a category</option>";
		foreach ( $rlv_categories_present as $cat_id => $cat_name ) {
			$select .= "<option value='$cat_id'>$cat_name</option>";
		}
		$select .= "</select>";
		$url = esc_url(remove_query_arg('paged'));
		if (strpos($url, 'page') !== false) {
			$url = preg_replace('/page\/\d+\//', '', $url);
		}
		$select .= <<<EOH
 
<script>
	<!--
	var dropdown = document.getElementById("rlv_cat");
	function onCatChange() {
		if ( dropdown.options[dropdown.selectedIndex].value > 0 ) {
			location.href = "$url"+"&cat="+dropdown.options[dropdown.selectedIndex].value;
		}
	}
	dropdown.onchange = onCatChange;
	-->
</script>
EOH;
 
		echo $select;
	}
}

For product categories, cat needs to be replaced with product_cat:

function rlv_category_dropdown() {
	global $rlv_categories_present, $wp_query;
 
	if (!empty($wp_query->query_vars['product_cat'])) {
		$url = esc_url(remove_query_arg('product_cat'));
		echo "<p><a href='$url'>Remove category filter</a>.</p>";
	}
	else {
		$select = "<select id='rlv_cat' name='rlv_cat'>
		<option value=''>Choose a category</option>";
		foreach ( $rlv_categories_present as $cat_id => $cat_name ) {
			$select .= "<option value='$cat_id'>$cat_name</option>";
		}
		$select .= "</select>";
		$url = esc_url(remove_query_arg('paged'));
		if (strpos($url, 'page') !== false) {
			$url = preg_replace('/page\/\d+\//', '', $url);
		}
		$select .= <<<EOH
 
<script>
	<!--
	var dropdown = document.getElementById("rlv_cat");
	function onCatChange() {
		if ( dropdown.options[dropdown.selectedIndex].value > 0 ) {
			location.href = "$url"+"&product_cat="+dropdown.options[dropdown.selectedIndex].value;
		}
	}
	dropdown.onchange = onCatChange;
	-->
</script>
EOH;
 
		echo $select;
	}
}

Once both functions are included in your theme, you can just add a

<?php rlv_category_dropdown(); ?>

to your theme search results template wherever you think is suitable.

  • The ability to filter out just posts from a certain category really helps the user to find what they need with just one extra click. This makes an already excellent plugin even more awesome! Thanks so much Mikko!