WordPress: how to add custom filters in post list admin area

Ever had a project where you needed to add custom filters in the admin area for a custom post type? Here is how it is done:

You will need to hook on the ‘restrict_manage_posts‘ filters to add your filter (dropdown) and to ‘parse_query‘ to alter the query according to the filter selection.

For example, if you want to add a filter to display a list of years for the user to select, add the following code in your functions.php file:


if (is_admin()){
   //this hook will create a new filter on the admin area for the specified post type
   add_action( 'restrict_manage_posts', function(){
        global $wpdb, $table_prefix;

        $post_type = (isset($_GET['post_type'])) ? quote_smart($_GET['post_type'], true) : 'post';
 
        //only add filter to post type you want
        if ($post_type == 'YOUR_POST_TYPE_HERE'){
            //query database to get a list of years for the specific post type:
            $values = array();
            $query_years = $wpdb->get_results("SELECT year(post_date) as year from ".$table_prefix."posts
                    where post_type='".$post_type."'
                    group by year(post_date)
                    order by post_date");
            foreach ($query_years as &$data){
                $values[$data->year] = $data->year;
            }

            //give a unique name in the select field
            ?><select name="admin_filter_year">
<option value="">All years</option>

                <?php 
                $current_v = isset($_GET['admin_filter_year'])? $_GET['admin_filter_year'] : '';
                foreach ($values as $label => $value) {
                    printf(
                        '<option value="%s"%s>%s</option>',
                        $value,
                        $value == $current_v? ' selected="selected"':'',
                        $label
                    );
                }
                ?>
            </select>
            <?php
        }
    });

    //this hook will alter the main query according to the user's selection of the custom filter we created above:
    add_filter( 'parse_query', function($query){
        global $pagenow;
        $post_type = (isset($_GET['post_type'])) ? quote_smart($_GET['post_type'], true) : 'post';

        if ($post_type == 'YOUR_POST_TYPE_HERE' && $pagenow=='edit.php' && isset($_GET['admin_filter_year']) && !empty($_GET['admin_filter_year'])) {
            $query->query_vars['year'] = $_GET['admin_filter_year'];
        }
    });
}

Using this technique you can actually add any filter you want.

You can read more about this here.