Using Query Posts With Multiple Post Types And A Taxonomy

The question:

I am developing a site that has two different custom post types; one of them is called Articles and one is called Sketchpad. Sketchpad is user submitted content that is assigned a custom taxonomy term value of either; public or private. Public posts are shown on the site and private posts aren’t.

The article post type caleld Articles is added in by administrators in the WordPress admin area, articles do not have a custom taxonomy.

On the homepage I need to pull out both “article” and “sketchpad” post type posts and then sort them by date with newer posts as the top and older ones at the bottom.

My current code is as follows:

        $args = array(
            'post_type' => array('sketchpad', 'article'),
            'taxonomy'  => 'type',
            'term'      => 'public'
        // Only show content from the sketchpad post type where the taxonomy of type is public

The code above works, to an extent. You see only the post type “sketcphad” has the taxonomy of type and a term value of “public” so the issue is the above query is also checking if posts of the type “articles” have the particular taxonomy and term value as well.

Is it possible to only make the taxonomy and term part of my query apply to the “sketchpad” post type and the post type of “article” doesn’t have any filtering criteria applied to it? Basically what I am wanting to do is merge two different queries into the one and output the results.

The Solutions:

Below are the methods you can try. The first solution is probably the best. Try others if the first one doesn’t work. Senior developers aren’t just copying/pasting – they read the methods carefully & apply them wisely to each case.

Method 1

not sure if you’ll have tried this yet but you could consider grabbing the two sets of posts separately then merging them. Finally use get_posts to create a combined list sorted the way you want. Something like this might work for you (you may want to add in a posts per page argument to the $args variables):

$sketchpad_args = array(
    'post_type' => 'sketchpad',
    'taxonomy'  => 'type',
    'term'      => 'public'
$sketchpad_posts = get_posts( $sketchpad_args );

$article_args = array(
    'post_type' => 'article',
$article_posts = get_posts( $article_args );

$all_posts = array_merge( $sketchpad_posts, $article_posts );

$post_ids = wp_list_pluck( $all_posts, 'ID' );//Just get IDs from post objects

// Do a new query with these IDs to get a properly-sorted list of posts
$posts = get_posts( array(
    'post__in'    => $post_ids,
    'post_status' => 'publish',
    'orderby' => 'date',
    'order' => 'ASC'
) );

foreach( $posts as $post ) :   
setup_postdata($post); ?>

// Your loop stuff

<?php endforeach; ?>

Method 2

Before answering, you should note that query_posts is never the way to go. Either you should use $myquery = new WP_Query() to generate a fresh query or you should filter the main query with pre_get_posts filter.

That said, lets assume you just want to know the query vars to pass into WP_Query, whether it’s by query_posts or new WP_Query.

I think that your situation is actually lucky in that the taxonomy you’re filtering against only has two terms. Because of that you can just EXCLUDE posts in the term you don’t want, rather than including the ones you do.

I.e. exclude ‘private’ sketchpads. That way the sketchpads get filtered like you want while all of the articles get returned, because none of them are in the ‘private’ taxonomy term.

You want to build a ‘tax_query’ array as part of your WP_Query with NOT IN as the operator.

FWIW I’d recommend using post metadata instead of a taxonomy for your private/public switch. Because it’s binary it will work fine in the postmeta table and ultimately the only UI you need for this is a checkbox, the whole taxonomy interface is overkill. Also worth noting is that with your taxonomy solution you ALWAYS have to set one of the taxonomy terms, either public or private, when really you can treat one as default (public) and have a checkbox for ‘private’. Less crap in your database and a checkbox instead of a complicated UI.

All methods was sourced from or, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

Leave a Comment