Exclude Categories from wp-query

This topic contains 2 replies, has 2 voices, and was last updated by  Josh Mason-Barkin 8 years, 1 month ago.

Viewing 3 posts - 1 through 3 (of 3 total)
  • Author
    Posts
  • #21843

    I’m trying to display certain events on my site’s front page using wp-query. It’s working, but not fully the way I need. (Admittedly, though I have lots of experience with wp-query, I’ve never really used tax_query. That may be where I’m getting tripped up.)

    I have several Event Categories in use. On the front page, I want to display all “sticky” events except those from three categories (call these “exclude-1,” “exclude-2,” and “exclude-3”). However, if an event has both one of the excluded categories and one of the included (or not excluded) categories, I want it to be displayed.

    Here’s an example of how I would do this with regular WP Posts:

    <?php
        $frontposts_args = array(
            'post_type' => 'post',
            'post__in'=>get_option('sticky_posts'),
            'post_status' => 'publish',
            'nopaging' => false,
            'order' => 'DESC',
            'orderby' => 'date',
            'cat' => '-35,-220,-145',
            'posts_per_page' => 3,
        )
        ?>
    <?php $frontposts = new WP_Query( $frontposts_args ); ?>
    <?php if ( $frontposts->have_posts() ) : ?>
    <?php while ( $frontposts->have_posts() ) : $frontposts->the_post(); ?>
    

    In this case, posts that are categorized with categories (by ID) 35, 220, and 145 aren’t displayed. Except if I add another category to a post (one that isn’t explicitly excluded), then the post appears. Huzzah!

    With Event Categories, I tried doing it like this:

    <?php
        $upcoming_args = array(
                  'post_type' => 'event',
                  'post__in'=>get_option('sticky_posts'),
                  'suppress_filters' => false, 
                  'posts_per_page' => 4,
                  'event_end_after' => 'yesterday',
                  'showpastevents' => false,
                  'orderby' => 'eventstart',
                  'order' => 'ASC',
                  'post_status' => 'publish',
                  'tax_query' => array (
                            array(
                            'taxonomy' => 'event-category',
                            'terms' => array('exclude-1', 'exclude-2', 'exclude-3'),
                            'field' => 'slug',
                            'operator' => 'NOT IN',
                            )
                        ),
                  'nopaging' => false,
        )
        ?>
    <?php $upcoming = new WP_Query( $upcoming_args ); ?>
    <?php if ( $upcoming->have_posts() ) : ?>
    <?php while ( $upcoming->have_posts() ) : $upcoming->the_post(); ?>
    

    The problem: When I do this, it excludes any events with the excluded categories, even those that also have other categories assigned. Is the solution to include all those other (non-excluded) categories, rather than excluding the three I want to exclude? Or maybe there’s just a better way to construct my query?

    Josh Mason-Barkin
    #21844

    Hi Josh,

    Here’s how WordPress converts the 'cat' attribute to a tax query:

    $tax_query[] = array(
         'taxonomy' => 'category',
         'terms' => $cat_not_in, //an array of IDs
         'field' => 'term_id',
         'operator' => 'NOT IN',
         'include_children' => true
    );
    

    So aside from the change of taxonomy, and using IDs rather than slugs, there’s no difference to what you have. I’m also suprised that 'cats' behaves as you describe (I’ve never noticed), because my interpretation is that it should exclude any posts that belong to those categories. In deed the codex says:

    Display all posts except those from a category by prefixing its id with a ‘-‘ (minus) sign.

    In any case, I think what you’re after is the following: “All events which are in event categories X, Y OR Z OR are have no category:

    $tax_query =array(
        'relation' => 'OR',
         array(
              'taxonomy' => 'event-category',
              'terms' => $whitelist, //an array of IDs
              'field' => 'term_id',
              'operator' => 'IN',
        ),
         array(
              'taxonomy' => 'event-category',
              'operator' => 'NOT EXISTS',
        )
    );
    

    You will obviously need to form $whitelist, which is an array of event category IDs which are not ‘exclude-1’, ‘exclude-2’ or ‘exclude-3’. To do that you can use get_terms() (see codex) – which allows you to retrieve term IDs (use the fields parameter) from a given taxonomy (event-category), which (via the exclude parameter) do not have any of a blacklist of term IDs. Of course, this means getting the term IDs of ‘exclude-1’, ‘exclude-2’, ‘exclude-3’ etc, but you can use get_terms() here again to do that.

    I hope that helps!

    Stephen Harris
    #21882

    Thanks for your help. That worked.

    [I didn’t bother defining $whitelist, since my list of event categories is pretty static. I just listed the IDs using 'terms' => array('1', '2', '3').]

    Josh Mason-Barkin
Viewing 3 posts - 1 through 3 (of 3 total)
To enable me to focus on Pro customers, only users who have a valid license for the Pro add-on may post new topics or replies in this forum. If you have a valid license, please log-in or register an account using the e-mail address you purchased the license with. If you don't you can purchase one here. Or there's always the WordPress repository forum.