Exclude categories everywhere*

Filters and Conditional Tags make it fairly easy to exclude categories, tags and custom taxonomies from the WordPress Loop as well as from custom queries. Widgets, however, seem to require a specific syntax in order to exclude categories from their queries. Candy: mini plugin inside!

Why exclude a category?

There are numerous use cases for excluding a category from WordPress queries. For my part, I use an excluded (“hidden”) category as a sort of private link archive. I would create a post, assign it to my hidden category and have the permalink redirected to another URL—the latter being a nifty feature of wpSEO, one of my favorite plugins.

set_query_var() vs. $query->set()

A common way of implementing the exclusion of a category from the main query in WordPress would be using pre_get_posts in conjunction with set_query_var().

But set_query_var() doesn’t seem to apply i.e. to the Recent Posts Widget. Using the unwrapped $query->set(), however, seems to do the trick.

Mini Plugin

For better reusability, I’ve wrapped a complete set of functions in a mini plugin. I have no plans to actively maintain this, so if it’s useful to you, feel free to make it your own.

What is a mini plugin?

A one-file plugin without any back-end options. Configure any parameters directly in the plugin file itself, upload to your plugins directory (or even make it a must-use plugin), activate from the backend and your done.

Download mini plugin from GitHub

So what’s the *catch?

There are still a couple of places left where posts of an excluded category would appear unless you create an extra filter. The main catch would be get_adjacent_post() which impacts the following common theme functions aka template tags:

  • next_post_link()
  • previous_post_link()
  • get_next_post_link()
  • get_previous_post_link()

In a nutshell, up to WordPress 3.9 get_adjacent_post() applies its own SQL query instead of using WP_Query. Hence, pre_get_posts() just doesn’t get any grip here whatsoever.

Trac Ticket #26937 aims to get get_adjacent_post() to use WP_Query, and the efforts look very promising. However, the ticket was originally scheduled for 3.9, but set to a future release lately as the whole undertaking seems to get pretty complex regarding backwards compatibility.

So, that’s the reason why you currently need to do one more thing to totally exclude a category from your front-end: Either, write up a filter for get_adjacent_post(), or set categories to be excluded directly in your theme files where next/previous_post_link() would occur. I am lazy and choose the latter to put it directly in a theme or child theme:

Anything left out?

I think this should pretty much wrap it up for excluding categories from the WordPress front-end. Anything you can think of that would need to be covered here?

Leave a Reply

Commenting is a privilege, not a right. Be good.

Your email address will not be published. Required fields are marked *