How to Create a WooCommerce Product Category Filter
We will take a look at two ways of creating an AJAX category filter for WooCommerce for your store. In case you don’t know, AJAX means that our filters will work fully without a page refresh:
- First, we will create product category filters for a WooCommerce block theme, using the WordPress Interactivity API.
- Second, if your store has been out there for many years, there is a big chance that you’re using a classic WordPress theme (for example, the Storefront theme), and I will take a look at that case as well.
Let’s dive into it.
Creating a WooCommerce Product Category Filter in Block Themes
If you’re using a WordPress block theme on your WooCommerce store, maybe it is one of the default ones like Twenty Twenty-Four or Twenty Twenty-Five, or maybe a theme from third-party developers, then the best way to create a filter by category is to use an interactive Gutenberg block, meaning that it uses the Interactivity API (specifically, routers).
Doing it completely from scratch could be a tough task. That’s why we will use a plugin.
The plugin Simple Taxonomy Filter Block will help us create different kinds of AJAX category filters for WooCommerce.
If you’re undecided about using it, you can check the examples on the demo page.
Examples of AJAX category filters in WooCommerce
I created the examples of product category filters below using:
- Product Collection – a default WooCommerce Gutenberg block (but you can also use the Query Loop block if you need),
- Twenty Twenty-Five – a WordPress default block theme.
First of all, you can display your filter as a dropdown (with or without multi-selection with checkboxes). More than that, this setup also allows you to filter products by tags, brands, and attributes (or any other custom taxonomy, by the way).

Another example of an AJAX category filter in WooCommerce is when the terms (categories, tags, brands, etc.) are displayed as a list of links:

Step 1. Insert the Taxonomy Filter block into the Product Collection block
If you want, you can display WooCommerce products using the standard “Query Loop” block, but there is no need for that at all, since there is the “Product Collection” block is available to you, which fully supports the Interactivity API, so we can easily create AJAX product filters.
You need to insert this “Product Collection” block into a template or a WordPress page you’re editing, or select an already inserted one; then navigate inside the block and insert the “Taxonomy Filter” block there.

Another thing you need to keep in mind, otherwise your product category filters will not work without a page refresh, is the “Reload full page” option toggle. It can be found in the block settings (either a “Product Collection or a “Query Loop”), in the “Advanced” section.

There was an issue back in the days when the Interactivity API had only rolled out that many blocks from the “WooCommerce Product Elements” section didn’t support it, which resulted in the “Reload full page” toggle being forced into the activated state.
I had even created a table below where I showed which block did or didn’t have support for AJAX. The good news is that today it is fully supported.
| WooCommerce Block | Does it support AJAX? |
|---|---|
| Product Title | Yes |
| Product Image | Yes |
| Add to Cart Button | Yes (you can also add products to the cart without a page refresh) |
| On-Sale Badge | Yes |
| Product SKU | Yes |
| Product Stock Indicator | Yes |
| Product Summary | Yes |
| Product Price | Yes |
| Product Rating | Yes |
| Product Categories | Yes |
| Product Tags | Yes |
Step 2. Configure the WooCommerce product category filter
Once the configuration of the product query loop is out of the way, we can dive into the product category filter settings.

Let’s take a quick look at each of them:
- Filter type – your AJAX category filter for WooCommerce can be displayed as a select dropdown, list of links, or buttons (similar to links but with style settings).
- Show post counts – near each product category, you can display a count with the number of products in it
- Taxonomy – you can select “Product categories”, “Product tags”, “Brands”, attributes, or any other custom taxonomy.
- All items text – the custom text you would like to display for the “All” option of the filter.
- Order by – in which order you’d like taxonomy terms (in our case, product categories) to be displayed in the filter.
- Limit number of visible items – can be helpful for link- or button-type filters when there are too many categories, and you don’t want them displayed in multiple rows.
- You can also switch to the “Styles” tab and configure text and background colors, font size, padding and margin, and borders.
If you have any questions about my Simple Taxonomy Filter Block plugin, feel free to ask them in the comments section below.
Filter WooCommerce Products by Category in Classic Themes
First of all, let me show you what our custom WooCommerce category filter is going to look like:

I am showing you an example with a category select dropdown list because it is easier in terms of HTML and JS; we don’t need to style active elements, and everything works super-simple with the jQuery change event. Of course, you can display categories as links or buttons.
By the way, in this chapter, we intend to create a WooCommerce AJAX product filter by category without a plugin. So there is going to be a lot of coding involved, and if you’re uncomfortable with it, please go back to the previous chapter.
But the whole process is not going to be very complicated, and it is very similar to how we did it for standard posts and categories.
Basically, there are going to be two steps:
- first, we create a product filter HTML,
- second, we send an asynchronous AJAX request using jQuery (yes) and process it in PHP with
wp_ajax_hooks.
Ok, let’s do this.
Step 1. Display a product category dropdown
There are no standard WooCommerce functions that allow getting product categories, but since it is just a custom taxonomy product_cat we can easily use get_terms() for that purpose.
Also, when working with WooCommerce, we don’t need to edit theme files or create a child theme because we can easily add our product category filter with a hook; for example woocommerce_before_shop_loop should be pretty much perfect for it.
Here is the code snippet for your theme functions.php or whatever:
<?php
add_action( 'woocommerce_before_shop_loop', function() {
?><form id="product-filter" class="woocommerce-ordering"><?php
$product_cats = get_terms( array(
'taxonomy' => 'product_cat',
'orderby' => 'name',
) );
if( $product_cats ) :
?>
<select name="product_cat">
<option value="">Select product category...</option>
<?php
foreach ( $product_cats as $product_cat ) :
?><option value="<?php echo $product_cat->term_id ?>"><?php echo $product_cat->name ?> (<?php echo $product_cat->count ?>)</option><?php
endforeach;
?>
</select>
<?php
endif;
?></form><?php
} );Some notes:
- I decided to use the
<form>HTML tag for convenience, in case later you decide to add more fields to our WooCommerce filter by category, after that it would probably not be by category only. - Form ID
product-filteris just a custom one, but I usedwoocommerce-orderingCSS class in order to make our filter look nice on the Storefront shop page. - Last but not least, you can also remove default product sorting and result count.
All right, here we go:

Now, we’re ready to connect some JavaScript events to it.
Step 2. Send and process an AJAX request every time a product category is selected in the filter
As I already mentioned before, I decided to choose a category dropdown as a <select> element, because it will be super-easy to create a JavaScript event for that. And right now, we’re going to do that.
Also, you may notice that I’m using jQuery. If you don’t like it, you can easily change it, but I would like to remind you that a lot of WooCommerce core functionality still relies on jQuery, and there is nothing wrong with that.
Let’s create a custom JavaScript file, let’s say filter.js, and put it into our plugin or theme folder (depending on where we’re implementing the product filter right now). Below is the code for that file:
jQuery( function( $ ) {
const productList = $( 'ul.products' )
$( 'select[name="product_cat"]' ).change( function() {
$.ajax( {
url: product_filter_args.ajaxurl,
method: 'POST',
data: $( '#product-filter' ).serialize(),
beforeSend: function( xhr ) {
// preloading effect, the same WooCommerce cart and checkout use
productList.fadeTo( '400', '0.7' ).block( { message: null, overlayCSS: { opacity: 0.7, backgroundColor: '#fff' } } );
},
success: function( data ) {
// remove preloading
productList.stop( true ).css( 'opacity', '1' ).unblock();
// add products to the list
productList.html( data );
// remove WooCommerce pagination
$( '.woocommerce-pagination' ).remove();
}
} );
} );
} );In this code, I would like you to pay attention to the jQuery BlockUI library I am interacting with; that’s what block() and unblock() methods are for. It basically allows us to display a nice preloader when your AJAX request is being processed.
Another question you might have is where I get product_filter_args.ajaxurl from. Easy – I’ve just provided the value for this variable with the help of the wp_localize_script() function at the same moment when I’m registering and enqueuing our filter.js script. You might also notice a jquery-blockui dependency in the code below as part of the wp_register_script() function because I am using the Block UI library.
add_action( 'wp_enqueue_scripts', function() {
// when doing it as a part of a plugin
// wp_register_script( 'mishafilter', plugin_dir_url( __FILE__ ) . 'filter.js', array( 'jquery', 'jquery-blockui' ), null, true );
// when doing it in a WordPress theme
wp_register_script( 'mishafilter', get_stylesheet_directory_uri() . '/filter.js', array( 'jquery', 'jquery-blockui' ), null, true );
wp_localize_script(
'mishafilter',
'product_filter_args',
array(
'ajaxurl' => add_query_arg( array( 'action' => 'productfilter' ), admin_url( 'admin-ajax.php' ) ),
)
);
wp_enqueue_script( 'mishafilter' );
} );Last but not least, we need to process our AJAX request somehow, and for that purpose, I’m just using a standard WordPress way – with the help of wp_ajax_ and wp_ajax_nopriv_ action hooks.
add_action( 'wp_ajax_productfilter', 'rudr_woocommerce_filter_by_category' );
add_action( 'wp_ajax_noprov_productfilter', 'rudr_woocommerce_filter_by_category' );
function rudr_woocommerce_filter_by_category() {
query_posts( array(
'post_type' => 'product',
'post_status' => 'publish',
'tax_query' => array(
array(
'taxonomy' => 'product_cat',
'terms' => $_POST[ 'product_cat' ],
)
)
) );
if( have_posts() ) {
while ( have_posts() ) {
the_post();
wc_get_template_part( 'content', 'product' );
}
} else {
echo 'No products found in this category.';
}
die;
}In this code, I decided to stick to the query_posts() function (instead of either WP_Query or get_posts()) because it allows us to set all the necessary global variables, which will be useful when we include a product template with the wc_get_template_part(). No need to use wp_reset_query() afterwards because we exit the code at the end anyway.
Misha Rudrastyh
Hey guys and welcome to my website. For more than 15 years I've been doing my best to share with you some superb WordPress guides and tips for free.
Need some developer help? Contact me
Hi, thank you for this great tutorial. I made ajax product filter with possibility to choose multiple categories + infinite scroll loader based on your other tutorial – it works great on product category listing, but on the main shop page I have a problem in one case – when I choose two or more categories in filter it renders first page of products, but when I want to load more with ajax then I get nothing – if I choose one category then it works great. Maybe you know what could be wrong?
Hi Lukasz,
How do you send multiple categories to the query? Comma-separated?