Filter Custom Post Type in Admin

I have a custom post type that has custom meta that I want to be able to filter on the Admin page. Much like the “All | Published | Drafts | and Trash” links located above the post list. I can’t seem to find a hook to hook into. Does one exist?

This question isn’t exactly what I am asking. I would prefer not to have the filter dropdown, but instead a link like …

Read More
All | Published | Drafts | Trash

… across the top of the editor.

Related posts

Leave a Reply

2 comments

  1. Just like in Adding a Taxonomy Filter to Admin List for a Custom Post Type? the filter parse_query could be used, but here I’m using posts_where.


    The row All | Published | ... is controlled by views_edit-{$post_type} and the $views array contains each item that’s a simple anchor tag.

    First, we insert a couple of links – a separator and a Meta filter:

    add_filter( 'views_edit-portfolio', 'meta_views_wpse_94630', 10, 1 );
    
    function meta_views_wpse_94630( $views ) 
    {
        $views['separator'] = '           ';
        $views['metakey'] = '<a href="edit.php?meta_data=allorany&post_type=portfolio">Meta Key</a>';
        return $views;
    }
    

    The link contains meta_data=allorany (the custom field name), which will be used to filter by meta key.

    enter image description here


    And then, filter when needed:

    add_action( 'load-edit.php', 'load_custom_filter_wpse_94630' );
    
    function load_custom_filter_wpse_94630()
    {
        global $typenow;
    
        // Adjust the Post Type
        if( 'portfolio' != $typenow )
            return;
    
        add_filter( 'posts_where' , 'posts_where_wpse_94630' );
    }
    
    function posts_where_wpse_94630( $where ) 
    {
        global $wpdb;       
        if ( isset( $_GET[ 'meta_data' ] ) && !empty( $_GET[ 'meta_data' ] ) ) 
        {
            $meta = esc_sql( $_GET['meta_data'] );
            $where .= " AND ID IN (SELECT post_id FROM $wpdb->postmeta WHERE meta_key='$meta' )";
        }
        return $where;
    }
    
  2. With credit to @brasofilo for his answer, it gave me all kinds of problems for a reason I couldn’t quite diagnose. I think the posts_where filter that gets added needs to be removed otherwise it will run for all future queries in the page and make a mess of anything that then tries to query a different post_type as the second filter will still be active.

    Here’s a solution that doesn’t require hacking the SQL manually, but works on the Query object instead. Assuming using the method of adding URL params as in the other answer here with url param name cpt_filter

    function filter_cpt($query) {
    
        global $pagenow;
    
        $cpt = "your_custom_type_name";
        $cpt_key = "some_key_to_filter_on";
        $cpt_value = "some_value_to_filter_for";
    
        if (is_admin() && $pagenow=='edit.php' &&
            isset($_GET['post_type']) && $_GET['post_type']==$cpt &&
            isset($_GET['cpt_filter'])  && $_GET['cpt_filter'] != 'None' &&
            $query->query['post_type'] == $cpt)  {
          
              $query->query_vars['meta_key'] = $cpt_key;
              $query->query_vars['meta_value'] = $cpt_value;
          }
        }
    
    }
    
    add_filter( 'parse_query', 'filter_cpt' );
    

    No problems here with adding/removing filters, and flexibility with setting the meta key and value to whatever works.