• Skip to primary navigation
  • Skip to main content
  • Skip to footer
  • Home
  • About
  • My Blogs
    • Photoblog
    • Knots
    • WP.com tips
kristarella.com

kristarella.com

Happiness Engineer at Automattic, lover of knitting, crochet, sci-fi and more

  • Presentations
  • Plugins
    • Exifography
  • Contact
You are here: Home / WordPress / Themes / Thesis / WordPress: Exclude child categories from category archives

WordPress: Exclude child categories from category archives

23 March 2010 by kristarella

Contents
  1. A normal category page
  2. “Solutions”
    1. category__in
  3. The real solution
    1. Before your category archive loop
    2. After the category page loop
  4. Modifying your Thesis category archive pages
    1. Before Thesis content
    2. After Thesis loop

A normal category page

I don’t know if you’ve noticed: on a WordPress category archive page, posts from that category and all its child categories are displayed. I don’t know why. It’s not the behaviour I would have expected, and although it’s not necessarily a bad thing, I can understand that some people wouldn’t want it that way.

“Solutions”

I used to have a nice little function that used the pre_get_posts filter to exclude all the child categories, but for some reason that function stopped working somewhere between WordPress 2.7 and 2.8 and I couldn’t for the life of me get it to work again, at least not the way I wanted.

Furthermore, a simple custom query like the one in my loop tutorial doesn’t work quite right; often it modifies the query so that it thinks it’s on a normal home/blog page (very noticeable if you use only titles, or excerpts on archive pages and not the home page).

category__in

For those in-the-know, you might be thinking, just use category__in: it gets the posts from that category ID and not the child categories. However, when I tried it, I didn’t like the results.

It turned out that the reason the results were a little funky is because setting category__in obliterates the cat query variable. Two specific impacts of that are that the single_cat_title() template tag doesn’t work (because it uses get_query_var('cat') to get the category title) and any plugin using get_query_var('cat') (including Yoast Breadcrumbs) won’t work.

I tried setting the cat variable along with category__in, but cat seemed to override such that the child categories were no longer excluded and adding category__not_in didn’t help either.

The real solution

The only real solution I could come up with was to use category__in before the loop and then reset the cat variable after the loop to allow plugins and widgets to use it.

Before your category archive loop

$paged = (get_query_var('paged')) ? get_query_var('paged') : 1;
$current_cat = get_query_var('cat');
$args=array(
	'category__in' => array($current_cat),
	'paged' => $paged
);
query_posts($args);

Note that the $paged bit is essential for maintaining pagination. I usually prefer to use $query_string in custom queries for that, but it doesn’t work in this case.

After the category page loop

Assuming the $current_cat variable is still in tact from before the loop:

set_query_var("cat",$current_cat);

Otherwise use category__in to figure out what category you’re in:

$cat = get_query_var('category__in');
set_query_var("cat",$cat[0]);

Note that category__in returns an array, so we need to use $cat[0] to get the first array value, which is the ID of the current category.

Now the cat query variable will be available for use before and after your loop. It won’t be available inside the loop, but after two days on the topic, I couldn’t find a way around that — if you do, let me know!

Modifying your Thesis category archive pages

If you would like to use this method in Thesis you need to insert the code before and after the loop with PHP via custom_functions.php.

Before Thesis content

This method presents another issue, because Thesis uses single_cat_title() in the archive info. So, when we set category__in the category name in the archive info will be blank. The following code initiates the custom query, removes the default archive info and adds a working archive info back in.

function remove_child_cats() {
if (is_category()) :
	$paged = (get_query_var('paged')) ? get_query_var('paged') : 1;
	$current_cat = get_query_var('cat');

	$args=array(
		'category__in' => array($current_cat),
		'paged' => $paged
	);

	query_posts($args);

	remove_action('thesis_hook_archive_info', 'thesis_default_archive_info');
		echo '			<div id="archive_info">' . "\n";
?>
				<p><?php _e('From the category archives:', 'thesis'); ?></p>
				<h1><?php echo get_cat_name($current_cat); ?></h1>
<?php
		echo '			</div>' . "\n";
endif;
}
add_action('thesis_hook_before_content','remove_child_cats');

After Thesis loop

function reset_cat_var() {
	$cat = get_query_var('category__in');
	set_query_var("cat",$cat[0]);
}
add_action('thesis_hook_after_content','reset_cat_var',1);

That’s it: a way to exclude child categories from category archive pages without breaking (too much) stuff.

Please feel free to ask (related) questions!

Share this:

  • Click to share on Facebook (Opens in new window) Facebook
  • Click to share on X (Opens in new window) X
  • Click to share on Pocket (Opens in new window) Pocket

Like this:

Like Loading...

Related

Filed Under: Thesis, Tutorials, WordPress Tagged With: PHP

Reader Interactions

Comments

  1. Craig Sunney says

    23 March 2010 at 20:45

    Genius

  2. gorostas says

    29 March 2010 at 05:02

    Hi,

    great post for first, I just wanted to say if you know for that plugin just_one_cat.php makes this parent cat problem with something like this:

    class Just_One_Category { var $q; function get_posts( &$q ) { $this->q =& $q; if ( !$q->is_category ) return false; add_action( 'posts_where', array( &$this, 'where' ) ); } function where( $where ) { global $wpdb; remove_action( 'posts_where', array( &$this, 'where' ) ); $cat = rtrim( $this->q->get( 'cat' ), ' /' ); if ( !is_numeric( $cat ) || $cat < 1 ) return $where; $field = preg_quote( "$wpdb->term_taxonomy.term_id", '#' ); $just_one = $wpdb->prepare( " AND $wpdb->term_taxonomy.term_id = %d ", $cat ); if ( preg_match( "#AND\s+$field\s+IN\s*\(\s*(?:['\"]?\d+['\"]?\s*,\s*)*['\"]?\d+['\"]?\s*\)#", $where, $matches ) ) $where = str_replace( $matches[0], $just_one, $where ); else $where .= $just_one; return $where; }}function joc_init() { $just_one_category = new Just_One_Category; add_action( 'pre_get_posts', array( &$just_one_category, 'get_posts' ) );}add_action( 'init', 'joc_init' );

    but youre solution is more flexible

  3. Sirkka says

    3 April 2010 at 01:14

    Smart tip there.

  4. greg says

    21 April 2010 at 14:12

    This is a gruesome WordPress bug that makes subcategories in default WP unusable in my opinion!

    Thank you for posting this, I spent several hours looking for this answer today, and then several hours trying to code it myself. I came up with a solution, but it was messy and annoying.

  5. kristarella says

    21 April 2010 at 14:26

    Greg — You’re welcome. Yeah, I spent a couple of days on this: not a full two days, but decent chunks over a couple of days before I figured out exactly what was happening where and how I could combat it… figured the least I could do was share!

  6. Adam Baird says

    21 May 2010 at 22:46

    You’re a lifesaver…actually looking to combat this exact problem this morning. Thanks!

  7. Michael Krapf says

    31 May 2010 at 12:17

    Yes!!! Thank you 😉

  8. Justin Bartlett says

    9 July 2010 at 17:34

    Is there a way to sort category teasers by a custom field – e.g. If all of the teasers of a category were an Event, for example, and each event has a “_date” custom field, how would I sort the teasers by the date of the event?

    All that I could find on possibly doing this was a code snippet posted online regarding the wordpress post query loop:

    query_posts(‘meta_key=_date&meta_compare=<=&meta_value=20&orderby=meta_value&order=DESC');

    And I guess my brain just can't make the connection between this code tidbit and how I'd implement it in Thesis.. Figured I'd ask the expert!

  9. kristarella says

    9 July 2010 at 18:11

    Justin — Assuming that bit of code works to modify the query as-is, you can use it in Thesis by hooking it before the content. I.e.,

    function custom_query() {
    	if (is_category('Event'))
    		query_posts('meta_key=_date&meta_compare=<=&meta_value=20&orderby=meta_value&order=DESC');
    }
    add_action('thesis_hook_before_content','custom_query');
  10. Justin says

    9 July 2010 at 20:14

    I was taking a look at the Thesis core files and I didn’t see any instances of “query_posts” so I’m pretty sure I’m … well… lost! I placed the bit of code into custom functions and of course it doesn’t modify the query as is. Oh boy! I have no idea whether to simply have the category page display nothing, and re-write a post loop that in effect creates teasers that I can then order by date or what to do! If you absolutely had to order a bunch of event posts by the date of the event how would you start to tackle it?

  11. kristarella says

    9 July 2010 at 22:51

    Justin — query_posts() can be used to create a query for a loop, but each page in WordPress already has a default query (e.g., the home page displays recent posts, category pages show recent posts from that category, single posts or pages etc), so Thesis doesn’t need to use the function. We can use it to modify the default query though.

    I have a feeling that your custom query doesn’t make sense. Basically what your query is saying is “show posts with the meta key ‘_date’ and whose meta value of that key is less than 20, order those posts in descending order according to that meta key”. You probably only need query_posts('meta_key=_date&orderby=meta_value&order=DESC');.

    Note that this modifies an existing query. Does this category page you’re referring to already have posts on it? If not you will have to write a whole custom loop. I don’t really have the full story on the custom field and why and how you’re using it, so I don’t think I can say much more, but I thought I’d just put it out there that you can change the publish dates of posts and pages, you might be able to use that to suit your purpose.

  12. Justin says

    9 July 2010 at 23:28

    Oh boy if this were a personal project I would have definitely taken a different approach and probably not given two hoots about chronological order of events in the first place. This is a case of Justin says to a friend, “Yes we can arrange those posts chronologically” (thinking, well, posts are naturally displayed chronologically), and “yeah bro I can make it easier for your users to add events by creating meta boxes”.

    Liittle did I know this would translate to – the custom field dates are going to determine the post order.

    I guess this all translates to I really should have looked into feasibility before I took the project!

    My original idea (to save time customizing) was to simply have the category page events and all subcategories of events display teasers, and that these teasers would be sorted by the custom field date.

    Interestingly, when I changed the Thesis settings back to displaying full posts on the category pages (same as home page, then selected the highest number of featured posts for no teasers), the query post function worked perfectly and sorted my posts by the date field!! ???? !!!

    I’m not sure why this worked. But the fact that it did work makes me a very happy Justin! And not looking like an dolt in front of a friend – priceless!

    So a little bit of conditional css based on the current category hiding .. eh.. everything but the headline, and adding back in the event date and a thumnail image – voila! I’ll soon (fingers crossed) have custom event category pages and subpages that actually sort by the date of the event, rather than the date of posting.

    Code bloated? Probably. Roundabout / is there probably a more direct way to do this? Most definitely. Happy I can get it done — heck yeah.

    I’m definitely not a programmer, and I’m thankful there’s awesome people with real smarts like you to help us non-tech savy, “it magically works now but I don’t understand it” types out!

  13. Gabriel says

    20 August 2010 at 05:20

    Hello Kristarella,

    I’m trying to add a category title to each category without manually adding one in.

    What I’d like to do is add the code with different text then “currently browsing” how-ever I’m trying to exclude certain categories. I am editing the archive page where the categories are displayed.

    Your help is much appreciated.

  14. Gabriel says

    20 August 2010 at 05:21

    The code was hidden. Here it is again: <?php single_cat_title(‘Currently browsing’); ?>

  15. kristarella says

    20 August 2010 at 11:44

    Gabriel — What theme are you using?

    If you want to use text different to “Currently browsing” then just change those words in the code you posted.

    Use conditional tags to restrict which categories it shows on. E.g., to NOT display the title on archive pages of the category Books and the category Technology:

    <?php
    if (!(is_category('Books') || is_category('Technology')))
      single_cat_title('You're looking at posts from the category');
    ?>
  16. Gabriel says

    20 August 2010 at 12:43

    Hi,

    I’m using a premium wordpress theme from studiopress.com

    I know I can change that text but let me explain a bit more. I’ve been very unclear in my initial post. Right now I have about 100 categories. Example: books, magazines, pdf … I want to add another string into the archive page for seo purposes. For example every page would say “Read (category) Free Online.” There are two category archives where I don’t want anything to be displayed as they are general categories.

    I’ve tried using your code above but I get a “Parse error: syntax error, unexpected T_STRING in…” Error.

    What else can you recommend?

    I

  17. kristarella says

    20 August 2010 at 12:51

    Gabriel — That is a PHP error and should be pretty easy to fix. Take a closer look at the error, it should tell you which line of which file the error is on. Unexpected T_STRING will generally mean you’ve forgotten some character before that bit, like a closing bracket or a semi-colon.

  18. Gabriel says

    20 August 2010 at 12:55

    Hi,

    Well the issue is with the 15th string. What I did was just pasted exactly what you typed in to test and see if it worked and get this error right away.

    Here’s the code:
    <?php get_header(); ?>

    <div id="content">

    <div id="contentleft">

    <div class="postarea">

    <?php include(TEMPLATEPATH."/breadcrumb.php");?>

    <div class="cat_description">

    <?php
    if (!(is_category(array(9,’blue-cheese’,’Stinky Cheeses’))
    single_cat_title(‘You’re looking at posts from the category’);
    ?>

  19. kristarella says

    20 August 2010 at 13:26

    Gabriel — As I mentioned, the error usually comes from something missing before the line with the error. You’re missing two closing parentheses at the end of line 14.

  20. Gabriel says

    20 August 2010 at 13:36

    Hi,

    Even when I add them I still get an error.

    I changed it to the code that you had suggested just to test it and i continue to get the error. Here’s a link to the whole archive php code.

    http://tinypaste.com/4b6bd3

  21. kristarella says

    20 August 2010 at 13:39

    Gabriel — Ok, that was the first error, then I made an error. It needs to be

    single_cat_title("You're looking at posts from the category");

    I shouldn’t have used single quote marks around the prefix when there was a single quote/apostrophe in it.

  22. Gabriel says

    20 August 2010 at 13:46

    Thank you very much, that works perfectly now. 🙂

    Enjoy the rest of your evening / night.

  23. Joel says

    11 March 2011 at 08:09

    I was using a plug in for this – and it doesn’t work with WP 3.1

    Once I put the code in custom_functions, do I do anything else? I think it works for some category pages but not all – I’m still investigating.

    Thanks

  24. kristarella says

    11 March 2011 at 08:18

    Joel — If you’ve got both of the last chunks of code in your functions you shouldn’t need to do anything else.

  25. Craig says

    11 March 2011 at 08:22

    @Joel….It’s still working for me after the upgrade to 3.1. Check this link to the finance category on this test site which also has child categories which are not showing: http://help-hub.com/c/finance/insurance-finance/

  26. Joel says

    11 March 2011 at 09:08

    Ah ha – there is a conflict of some kind with other customization I added for this category. For a couple of category pages on our site (including this “Our Designers”) I have some customization to display only teasers. When I take that category ID out of the code, I get only the posts for the parent category – which is what I want. But now I get one “feature post” then teasers – which I don’t want.

    Thanks you for the quick replies!

    @Craig – I haven’t had a chance to look at your site yet but were you using “Just one Category”? Once I upgraded things went a south (no offense Kritarella!)

  27. kristarella says

    17 March 2011 at 20:24

    Joel — What was the other customisation that wasn’t compatible with this? Perhaps we can find a way to integrate them.

  28. Joel says

    18 March 2011 at 04:42

    Should I send the code or post it? It makes all posts on specified categories pages teasers.

  29. Joel says

    18 March 2011 at 04:55

    I’ll go ahead and post it – thank you for taking a look!

    Here is the code that is supposed to show posts as teasers only for the specified category (I don’t recall where I stole it) It’s in custom_functions.php, just before the parent only code.

    /*******************************************************************************
    * show only teasers in selected category pages
    *******************************************************************************/

    $ttw_alternate_category_loop = new ttw_custom_category_loops;

    class ttw_custom_category_loops extends thesis_custom_loop {
    function category(){

    $alternate_categories = array(‘141′,’79’); //specify categories as list: = array(‘4′,’6’);

    if(is_category($alternate_categories)){
    thesis_archive_intro();
    $paged = (get_query_var(‘paged’)) ? get_query_var(‘paged’) : 1; // necessary for paging
    $post_cut_off = 10; // set the number of posts to show per page
    $ttwcat_current_cat = get_query_var(‘cat’); // necessary for the other functions below
    $teaser_count = 1;

    query_posts (array( // New query vars
    ‘posts_per_page’ => $post_cut_off,
    ‘paged’ => $paged,
    ‘cat’ => $ttwcat_current_cat)
    );

    while (have_posts()) { #wp
    the_post(); #wp

    if (($teaser_count % 2) == 1) {
    $top = ($post_count == 1) ? ‘ top’ : ”;
    $open_box = "\t\t\t<div class=\"teasers_box$top\">\n\n";
    $close_box = ”;
    $right = false;
    }
    else {
    $open_box = ”;
    $close_box = "\t\t\t</div>\n\n";
    $right = true;
    }

    if ($open_box != ”) {
    echo $open_box;
    thesis_hook_before_teasers_box($post_count);
    }

    thesis_teaser($classes, $post_count, $right);

    if ($close_box != ”) {
    echo $close_box;
    thesis_hook_after_teasers_box($post_count);
    }

    $teaser_count++;
    }
    if ((($teaser_count – 1) % 2) == 1)
    echo "\t\t\t</div>\n\n";
    }
    else{
    thesis_loop::category();// Use the default category loop
    }
    }
    }

  30. kristarella says

    18 March 2011 at 09:28

    Joel — Looks to me like if you used category__in instead of cat in your query, then that would fix your problem?

  31. Joel says

    19 March 2011 at 01:57

    Bingo! That did it.

    Thanks very much for the help.

  32. Jennifer Heller says

    25 May 2011 at 03:58

    Hey Kristarella,

    Thanks for this and for your many other great tutorials. We want to use Thesis’ Introductory Headline and Introductory Content above our individual category archives. Somehow this stops working when I implement your code, even if I take out:
    remove_action(‘thesis_hook_archive_info’, ‘thesis_default_archive_info’);
    echo ‘ ‘ . “\n”;
    ?>

    <?php
    echo ' ‘ . “\n”;

    I’ve tried combing through the code to find out how to call those variables to no luck. Can you help?

    Thank you!!

  33. Fatih Toprak says

    12 August 2011 at 06:10

    Hey Kristarella,

    For example;

    video cat id = 4 video cat child category id’s = 7,8,9
    news cat id = 5 news cat child category id’s = 11,12,13

    I wanna display choosen categories ( like video and news ) in the different archive.php?

    Is it possible thanks.

    ( sorry about my bad Eng )

    p.s. could you write example loop for this please

  34. kristarella says

    25 August 2011 at 09:11

    Jennifer — I’m not sure what the problem is, I don’t think the code you posted came through properly. Perhaps if you put your custom_functions.php file in Pastebin for me I could see what’s wrong.

    Faith — I’m not sure what you mean, but perhaps this post on loops will help you.

  35. Kyathi says

    6 September 2011 at 19:52

    Nice post

  36. Jennifer says

    9 September 2011 at 06:18

    Thank you Kristerella for the response. I actually got this fixed via the forums. You were a great help there too. Thanks again.

  37. Robert Lovrekovic says

    7 November 2011 at 03:34

    Thank you thank you thank you!!!! I tried every other solution and non work. I lost over 5 hours to figure that out. This is the only solution that worked perfectly. Thank you

    Continue with a great job, well done.

  38. Mohamamd says

    24 November 2011 at 19:48

    Where should I exactly put the 2 codes? function?

    I’m using a custom theme.

    Thanks,

  39. kristarella says

    24 November 2011 at 21:51

    Mohamamd — It depends on the theme. I’ve shown how to do it in Thesis, other themes might have a similar method using functions.php, or you might have the edit the category.php theme file.

  40. serge says

    5 February 2012 at 11:34

    Hi Kristen, saw your little snippet on pre_get_posts stopped working back in 2.8 ? I have coded it back – see here http://thesistut.com/2012/excl.....-category/

    cheers,
    serge

  41. Steve says

    10 February 2012 at 09:39

    Hi,
    I’ve implemented this code and it’s working great, only problem is it has stopped the ‘Search’ feature working. I know the search is finding results, but it’s not outputting them, I can also see that the search uses the loop.php code to display the results. I think I need to put a conditional statement around the this code so the search will not use the category restriction, but I’ve no idea how to do this, any suggestions appreciated.

    Thank you.

  42. serge says

    10 February 2012 at 10:27

    Hi Steve, try the code from the link in my previous comment (#40) . It does not interfere anywhere else except for the targeted category pages.

    Cheers,
    Serge

A triptych of baubles. These are very satisfying t A triptych of baubles. These are very satisfying to paint ❤️💚💙

#watercolor #watercolour #christmas
I have really enjoyed this Christmassy painting! S I have really enjoyed this Christmassy painting! So glad my friend asked me to make some cards for our church helpers, because it set me on a roll!
#watercolor #watercolour #christmas #christmascards #watercolorcards
Had a great Saturday at the GKR Karate State Title Had a great Saturday at the GKR Karate State Titles! I was a sub for @jamesxuereb.me in the Blue Flame Dragons thanks to his sprained ankle; we won first round and came fourth overall!
I did a bunch of judging and officiating, which was really good.
I didn’t place in my individual events, but had a very fun final round of kumite (sparring).

#gkrkarate #karate
More stamping tonight. Even better than last night More stamping tonight. Even better than last night’s!
Did some stamping this evening. Love it! I wish I’d done some pages in other ink colours before I dismantled the stamps 😂
Had an appointment in the city, so I got to visit Had an appointment in the city, so I got to visit the @legocertifiedstores_anz Wicked display!
#wicked #lego #afol #sydney
A little book I made from Bunnings paint sample ca A little book I made from Bunnings paint sample cards. It’s going to be for mini paintings and collages. Sometimes it’s nice to start with a colour rather than a blank white page!
A little while ago I did some swatching of Daniel A little while ago I did some swatching of Daniel Smith and Schminke Horodam watercolours. So soothing! I love some of the granulating colours!
#watercolours
Follow on Instagram

Footer

Subscribe to Blog via Email

Enter your email address to subscribe to this blog and receive notifications of new posts by email.

Top Posts & Pages

  • Sistaco Nail Powder Review
    Sistaco Nail Powder Review
  • Home
    Home
  • Boobs & Dinks - early cancer detection
    Boobs & Dinks - early cancer detection
  • Edit EPS files in Inkscape on Mac
    Edit EPS files in Inkscape on Mac
  • Exifography
    Exifography

Follow Me On…

  • Instagram
  • X
  • GitHub
  • LinkedIn
  • YouTube

Categories

Copyright © 2025 · Kristen Symonds · kristarella.com

%d