Today I needed to exclude a category from the main WordPress posts feed, the one you’ll find at http://mywordpresssite.com/feed/; however I didn’t want to exclude posts in that category from other feeds (especially not from that category’s feed at http://mywordpresssite.com/excluded-category/feed/). Here’s how I set about it…
Here’s the code snippet for y’all:
/* Copyright 2011 Simon Wheatley This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /** * Hooks the WP pre_get_posts action to remove posts in particular categories * from the feed, by interfering with the WP Query object. * * @param object $wp_query The WP Query object * @return void **/ function sw_pre_get_posts( $wp_query ) { // Only for feeds if ( ! is_feed() ) return; // Restrict to the main feed... // ...NOT category feeds if ( $wp_query->query_vars[ 'category_name' ] ) return; // ...NOT comment feeds if ( $wp_query->query_vars[ 'withcomments' ] ) return; // ...NOT tag feeds if ( $wp_query->query_vars[ 'tag' ] ) return; $ex_cats = array(); // Exclude Photos category $photos = get_term_by( 'slug', 'photos', 'category' ); $ex_cats[] = $photos->term_id; // Because the WP Query object is passed by reference, we // can just act on it here without needing to return. set_query_var( 'category__not_in', $ex_cats ); } add_action( 'pre_get_posts', 'sw_pre_get_posts' );
The action I’m using is pre_get_posts
, which is fired before the WP Query object puts together or uses the DB query to get the posts, and after the query parameters have been established. This action is a perfect time to monkey around with the query parameters.
Before I get down to the monkey business, I run a series of checks to ensure that we are querying posts for a feed, and that it isn’t a category, tag or comments feed. (If anyone knows a way to positively test for the main site feed, rather than negatively testing that it isn’t one of the other feeds, please let me know.)
Once I’m sure I’m altering the right feed, I assemble an array of term IDs. I’m doing this by retrieving the category terms by slug, this ensures seems clearer to me than directly inputting term IDs as slugs are less likely to change between sites (so if you want to use this plugin on a number of sites then the code won’t need to change as much, and if it does change a slug is more obvious than an abstract number like a term ID). Once this is done, I use the set_query_var
function to set the category__not_in
var, which will ensure that no posts in the chosen categories are returned. (N.B. at the time of writing, the child categories of excluded categories are not checked… the posts excluded must be explicitly within the categories given in order to be excluded.)
That’s it… check through the code (link above) and let me know if you’d do anything different. Hope it helps.
Thanks for sharing this code, it is close to what I am looking for. However, what I need is a bit different…and I think simpler code-wise. I would like to exclude a category from all feeds except the feed for that particular category. I was looking at your code, but can’t figure it out. Do you have a second to take a shot at it? Also, I would like to use the category ID instead of the slug to exclude it.
I know this is a few years old, but thanks for sharing this. It helped me get my site set up with micro.blog just how I wanted it, with only posts of category “microblog” getting fed via RSS to micro.blog, and not to my main feed.