get_posts that haven’t been assigned a specific custom field

I’m trying to use get_posts() to pull articles that have not been assigned a specific custom field. For example (not working):

$articles = get_posts(array(
  'post_parent' => 0,
  'post_type' => 'custom-type',  
  'meta_query' => array(
    array(
      'key' => 'alternate_page',
      'value' => array(0, '', null),
      'compare' => 'IN'
    ),
  )         
));

Basically, I want all ‘custom-type’ articles that don’t have a parent and don’t have the ‘alternate_page’ custom field assigned.

Read More

I’ve read elsewhere about doing two queries, one for all articles that have the custom field, getting and array of their IDs, and using the ‘__post_not_in’ parameter, but this seems tedious.

Is it possible to do in one query like above? Thanks.

Related posts

Leave a Reply

1 comment

  1. You can do it with a posts_where filter and a subquery. Note that you have to explicitly set suppress_filters to false, as get_posts normally ignores filters:

    function wpse28018_posts_where( $where ) {
        global $wpdb;
        $where .= " AND {$wpdb->posts}.ID NOT IN ( SELECT DISTINCT post_id FROM {$wpdb->postmeta} WHERE meta_key = 'alternate_page' )";
        return $where;
    }
    
    // add the filter
    add_filter( 'posts_where' , 'wpse28018_posts_where' );
    
    // do the query
    $articles = get_posts(array(
      'post_parent' => 0,
      'post_type' => 'custom_type',  
      'suppress_filters' => false     
    ));
    
    // remove the filter so other queries aren't affected.
    remove_filter( 'posts_where' , 'wpse28018_posts_where' );