Show only WooCommerce products in the default WordPress search

In a project, the design agency had created a theme without a search template (though manual searches were still possible). Now, the shop owners wanted to have a search in the header of the page, but it should only search for products.

Some themes have this implemented in the header search already, like the “default theme” Storefront. Others have the regular WordPress search, which would always search for all post types. Let’s see, how we can change this.

Find only products

In WordPress, you can add ?s=something to any URL and this would search the WordPress site for any public post types, that does not have exclude_from_search set to true in its registration settings. But if we only want searches to find products, we can achieve this in different ways.

Use a hidden field to set the post type

If we look into the source code of the header in the Storefront theme, we will find the following HTML code:

<form role="search" method="get" class="woocommerce-product-search" action="https://woocommerce.ddev.site/">
	<label class="screen-reader-text" for="woocommerce-product-search-field-0">Search for:</label>
	<input type="search" id="woocommerce-product-search-field-0" class="search-field" placeholder="Search products&hellip;" value="" name="s" />
	<button type="submit" value="Search" class="">Search</button>
	<input type="hidden" name="post_type" value="product" />
</form>

As the placeholder text is indicating, the search field is only for products. This is achieved by adding a hidden field setting the post_type to product for this search. When submitted, the search would open a URL like https://example.com/?s=something&post_type=product. This would then only show products and use the archive-product.php template, if available in the theme. This would list the search results in the same way as in the shop (in most themes).

Redirect the normal search to the shop

Even with this modification in place, it’s still possible to search for any other post type, by adding the search parameter to any non-shop URL, as mentioned in the beginning. If we really want to restrict normal search and only allow product searches, we could redirect any normal search to the shop search. This can be done with a snippet like this:

function product_search_only_redirect_search_to_products() {
	if ( is_admin() ) {
		return;
	}

	if ( ! is_search() ) {
		return;
	}

	// We are already at the right search result page.
	if ( is_shop() || is_tax( get_object_taxonomies( 'product' ) ) ) {
		return;
	}

	$search_query = get_search_query();
	$shop_url     = wc_get_page_permalink( 'shop' );
	$redirect_url = add_query_arg( 's', rawurlencode( $search_query ), $shop_url );
	wp_safe_redirect( $redirect_url );
	exit();
}
add_action( 'template_redirect', 'product_search_only_redirect_search_to_products' );

In this callback function to the template_redirect action, redirect any frontend search, that is not already done on the shop or a taxonomy archive page. This prevents any normal search. If we now search on the page, we get redirected to a URL like https://example.com/shop/?s=something and would only see products.

Bonus tips

I’ve opted for the second option, as the shop theme didn’t have a generic search template (in fact it had one, but it would just print an empty page with only the header and footer). After this implementation, we found two small issues – not with this solution, but generally with how the search worked.

Remove empty search terms from the template header

I also added a search field to the “filter drop-downs”. This had the effect, that every time one of the filters would be used, the page would submit, sending an empty search term. This would result in a URL like https://example.com/shop/?s= title on that page like this: Search results: “” instead of something like Shop. To fix this, I’ve added the following snippets:

function product_search_only_clear_empty_search_from_request( $wp ) {
	if ( isset( $_GET['s'] ) && empty( trim( $_GET['s'] ) ) ) {
		unset( $wp->query_vars['s'] );
	}
}
add_action( 'parse_request', 'product_search_only_clear_empty_search_from_request' );

Prevent the search redirecting to a single product

The second issue was recognized by the shop owner. Any time there would be only one product as a result of a shop search, it would not show this result with the “product archive” template, but redirect to that single product. And since we redirected all searches to the shop search, this would be the case for any search that would only find one product, which could be confusing. Fortunately, by digging into the source code of WooCommerce to find the place where this is happening, I’ve found a filter to disable that redirect. All I had to do was adding one more line of code:

add_filter( 'woocommerce_redirect_single_search_result', '__return_false' );

That’s it! Now the search would always show a list of products, or just a single one, but not automatically redirect to that one product.

Conclusion

I’m not really a WooCommerce expert, quite the opposite. But since WooCommerce Core is using the same techniques as WordPress itself, I can usually find ways to customize it in the way I need it to be.

If you want this on your WooCommerce installation, you can find the code as a plugin in a GIST, where you can also download it as a ZIP and install it on your site.

If you have any other tips around searches in WooCommerce, please leave a comment.

Posted by

Bernhard is a full time web developer who likes to write WordPress plugins in his free time and is an active member of the WP Meetups in Berlin and Potsdam.

Leave a Reply

Your email address will not be published. Required fields are marked *