Excluding one category from the main WordPress feed

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.

One thought on “Excluding one category from the main WordPress feed

  1. Tony

    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.

    Reply

Leave a Reply

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

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>