The WordPress post list can already be filtered by built-in conditions such as date and category, but in many projects those defaults are not enough. We can also add our own custom filters as needed. The feature mainly relies on the restrict_manage_posts and parse_query hooks. In this article, we will use those hooks to add a filter based on a custom field in the WordPress admin. The result looks like this:

Step 1: Add the filter form field
The first step is to add a dropdown field to the WordPress admin post list. We start with a few checks, then read the available filter values from the WordPress database, and finally build a <select> field from those values. In real use, you should replace the custom field name and post type name with the ones from your own project.
add_action('restrict_manage_posts','cpt_type_filter',10);
function location_filtering($post_type){
if('my-custom-post' === $post_type){
return; // Check whether this is the post type we want.
}
$selected = '';
$request_attr = 'my_loc';
if ( isset($_REQUEST[$request_attr]) ) {
$selected = $_REQUEST[$request_attr];
}
// The meta key used for filtering.
$meta_key = 'my_custom_field_location';
// Fetch the filter values.
global $wpdb;
$results = $wpdb->get_col(
$wpdb->prepare( "
SELECT DISTINCT pm.meta_value FROM {$wpdb->postmeta} pm
LEFT JOIN {$wpdb->posts} p ON p.ID = pm.post_id
WHERE pm.meta_key = '%s'
AND p.post_status IN ('publish', 'draft')
ORDER BY pm.meta_value",
$meta_key
)
);
// Build the dropdown from the values we fetched.
echo '';
}
Step 2: Add the filter condition to the post-list query
The first step only adds the custom filter field to the form. To make the filter actually work, we still need to process the request after the form is submitted and inject the selected value into the query used by the admin post list. The code below shows the basic implementation.
add_filter( 'parse_query', 'filter_request_query' , 10);
function filter_request_query($query){
// Only modify the main query on the admin post list screen.
if( !(is_admin() AND $query->is_main_query()) ){
return $query;
}
// If this is not our target post type and the custom query var is set, return the original query.
if( !'my-custom-post' === $query->query['post_type'] or !isset($_REQUEST['my_loc']) ){
return $query;
}
// If the custom filter is still at its default value, return the original query.
if(0 == $_REQUEST['my_loc']){
return $query;
}
// Modify the query vars.
$query->query_vars = array(array(
'field' => 'my_custom_field_location',
'value' => $_REQUEST['my_loc'],
'compare' => '=',
'type' => 'CHAR'
));
// Return the modified query.
return $query;
}
After these two steps, the WordPress admin post list can be filtered by that custom field. And this same idea is not limited to custom fields. In theory, any parameter supported by WP_Query can be turned into an admin-side filter, including author, custom taxonomies, tags, and other conditions.
