When I wrote my first WordPress related post, I admitted that I was only doing it to attract traffic and it would be my last post on the subject. However, I start again. This time around, however, I want to talk about something which isn’t common knowledge and neither did I get any responses on the official WordPress forum regarding this.
Suppose you do not want some of your posts to appear anywhere: not the homepage, not the RSS feeds, not the archives: nowhere. However you DO want it to appear only when its linked to, as a single post on the page. I regularly need to do this, because some part of the post is more like an ‘addendum’ or when including everything would make the post too long.
There is a standard solution available on the forums: creating a plugin and adding code to this effect:
function hs_cat_exclude($query)
{
if ($query->is_feed || $query->is_home || $query->is_archive ) {
$hsq = $query->gt;get('cat');
if (!isset($hsq)) {
$hsq = '-22';
}
else {
$hsq = $hsq . ",-22";
}
$query->gt;set('cat',$hsq);
}
return $query;
}
add_filter('pre_get_posts','hs_cat_exclude');
Here, 22 is the category number of the category I wanted to exclude.
This code works fine, but the moment you add is_category
to the ‘if
‘ clause, it doesn’t work for the category page. This was perplexing to me, and I did not understand it. I spent a long time and then decided to dig deeper. I found out that the ‘wiring’ is faulty (this is what I believe). It can’t work like this for the category page. What is needed additionally is something like this:
function hs_cat_exclude_cat($where)
{
global $wp_query;
if ($wp_query->is_category) {
$where = $where . " AND NOT EXISTS(SELECT 1 FROM wp_term_relationships WHERE wp_term_relationships.object_id=wp_posts.id AND wp_term_relationships.term_taxonomy_id='22')";
}
return $where;
}
add_filter(‘posts_where’,’hs_cat_exclude_cat’);
So far so good. What I wanted over and above this though, is for the category to not even appear on the category widget. I tried to find a way to get this done through the plugin but it did not work. Ultimately I had to ‘hack’ one of the core files to achieve this. If anyone knows of a better way to accomplish this, please add a comment. The change is to wp-includes/widgets.php
. Find the line of code that looks like:
$cat_args = array('orderby' => 'name', 'show_count' => $c, 'hierarchical' => $h);
added an ‘exclude’ clause like this:
$cat_args = array('orderby' => 'name', 'show_count' => $c, 'hierarchical' => $h, 'exclude' => 22);
Thats all there is to it.
Update Jan 12th 2010: Since WP 2.8 I believe (I noticed the problem in 2.9.1), the last change above needs to be done to
default-widgets.php
rather thanwidgets.php