How to Create a Custom Order Filter in WooCommerce Admin

In this guide I am going to show you how you can easily create a custom order filter for the WooCommerce > Orders page, which will work great for both CPT-based and HPOS orders.

In order to keep this tutorial as simple as possible we’re going to create a filter just by a single custom field value. This is how it is going to look:

how to create an order filter by a custom field in WooCommerce admin

Add a Field into the Order Filter Form

At this very first step we’re just going to add a select dropdown field before the “Filter” button here:

Add a field into the WooCommerce order filter

And we can do it with the help of one of the following hooks:

What is great about these two hooks is that the first parameter in both of them is a custom post type name! Yes, it is made in terms of backward compatilibty and basically it allows you to use a single function for both of the hooks at the same time, let me show you how:

<?php
	add_action( 'woocommerce_order_list_table_restrict_manage_orders', 'rudr_order_filter', 25, 2 );
	add_action( 'restrict_manage_posts', 'rudr_order_filter', 25, 2 );

	function rudr_order_filter( $post_type, $which ) {
		
		if( 'shop_order' !== $post_type ) {
			return;
		}
		
		$rudr_custom_field = isset( $_GET[ 'rudr_custom_field' ] ) ? $_GET[ 'rudr_custom_field' ] : '';

		?>
			<select name="rudr_custom_field">
				<option value="">Custom field</option>
				<option value="value-1"<?php selected( $rudr_custom_field, 'value-1' ) ?>>Value 1</option>
				<option value="value-2"<?php selected( $rudr_custom_field, 'value-2' ) ?>>Value 2</option>
			</select>
		<?php

	}

Nothing to explain here, just don’t forget to provide a name HTML attribute for your form field and please pay attention to the line 11, we need it to prevent PHP notice from happening.

The $which argument value can be either top or bottom.

Filtering the Orders

Great, the field is added but of course it doesn’t work at this moment! Not always the case by the way, but in our situation we need to filter order with another hook.

Here we have two hooks again and we need to choose one depending on whether we’re using high performance order storage or not (or use both of them if you need to maintain backward compatibility).

The first hook example:

add_action( 'woocommerce_order_list_table_prepare_items_query_args', function( $query_args ) {

	if( isset( $_GET[ 'rudr_custom_field' ] ) && $_GET[ 'rudr_custom_field' ] ) {
		$query_args[ 'meta_query' ] = array(
			array(
				'key' => 'rudr_custom_field',
				'value' => $_GET[ 'rudr_custom_field' ],
			)
		);
	}

	return $query_args;

} );

The second hook example:

add_action( 'pre_get_posts', function( $query ) {
	
	if( ! is_admin() ) {
		return;
	}

	global $pagenow;
	// just being super-accurate here
	if( 'edit.php' !== $pagenow || 'shop_order' !== $query->get( 'post_type' ) ) {
		return;
	}
	
	if( isset( $_GET[ 'rudr_custom_field' ] ) && $_GET[ 'rudr_custom_field' ] ) {
		// also works
		// $query->set( 'meta_key', 'rudr_custom_field' );
		// $query->set( 'meta_value', $_GET[ 'rudr_custom_field' ] );
		$query->set( 'meta_query', array(
			array(
				'key' => 'rudr_custom_field',
				'value' => $_GET[ 'rudr_custom_field' ],
			)
		) );
	}

} );

As you can see the code is kind of similar so maybe you will find a way to put the same PHP function on both hooks how we did it in the first example in the beginning of the tutorial.

Misha Rudrastyh

Misha Rudrastyh

Hey guys and welcome to my website. For more than 10 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

Follow me on X