WordPress: How to Sort Category Archive Posts by Subcategory

By default, WordPress sorts posts in reverse chronological order, with the most recent post being at the top and the least recent at the bottom. Normally, that’s totally cool, since that’s the way we’ve been accustomed to reading blogs, but what about when you’d like a little more organization?

Let’s say, for example, we’ve got a Music category with music genres as subcategories and posts specific to those genres organized respectively:

  • Music
    • Rock
      • “The History of AC/DC”
    • Hip Hop
      • “What Ever Happened to Bell Biv Devoe?”
    • Pop
      • etc
    • Jazz
    • etc

When viewing the Music category archive, these subcategory posts will be displayed all mixed in together and in reverse chronological. What we’d rather have is each subcategory given its own individual listing of its posts, prefaced by an H2 title and subcategory/genre description. We’ll order the subcats alphabetically; their posts chronologically.

To do this, we’ll modify/create a category template for our Music category, in my case, category-17.php.

We’ll use the get_categories() WordPress function to create an array of the current category’s subcategories.

<?php $categories = get_categories("child_of=17"); 

The child_of parameter tells the function to grab all the child categories of 17, the ID for our Music category. You’ll substitute whatever ID your category is. The function will automatically order the subcats alphabetically, but you can also set it to order by ID.

Next, we’ll use PHP’s foreach construct to iterate through each array asset, find its subcat ID, and query_posts() to grab that subcat’s posts.

foreach ($categories as $cat) {
	query_posts("cat=$cat->cat_ID&showposts=-1&order=ASC&orderby=name");

The showposts=-1 parameter tells query_posts to grab all the posts without stopping at the default number for your installation, and order=ASC orders them in normal chronological order (default is DESC, descending).

Then we use a simple WordPress loop to display that post’s goodies, close the foreach(), and let it go on to the next subcat.

Finished code:

<?php $categories = get_categories("child_of=17"); foreach ($categories as $cat) { ?>
	<div class="genre_subcat">
		<?php query_posts("cat=$cat->cat_ID&showposts=-1&order=ASC&orderby=name"); ?>
		<h2><?php single_cat_title(); ?></h2>
		<small><?php echo category_description($cat->cat_ID); ?></small>
		<?php while (have_posts()) : the_post(); ?>
			<div class="post">
				<h3><a href="<?php the_permalink() ?>" rel="bookmark" title="Permanent Link to 
				<?php the_title_attribute(); ?>"><?php the_title(); ?></a></h3>
				<p class="postdate"><?php the_time('F jS, Y') ?></p>
				<?php the_content(); ?>
				<p class="postmetadata">Posted in <?php the_category(', ') ?> | 
				<?php comments_popup_link('No Comments', '1 Comment', '% Comments'); ?></p>
			</div>
		<?php endwhile; ?>
	</div>
<?php }?> 

Explanation:

We grab an array of the category’s children, iterate through each one, make a new “genre_subcat” DIV, query the subcat, display a subcat header and description, loop through the posts with a while (have_posts()) construct, and finally display each post in a DIV with an H3 and some metadata, all before closing the while and querying the next subcategory in the array.

Of course, this is sort of a skeleton of what you could do, but you get the idea. Yay! Sorting a category’s posts by subcategory! Yayy!!

  • Vince

    Thanks for the lesson, my brain now has one more wrinkle in it

  • http://www.rotatingcorpse.com/ Jim

    This is a really interesting tutorial! Great job!
    But I was wondering, what if I wanted the index page to show posts by date (just like it does now by default), then list posts with the same date by cat id? Could I apply the kind of logic you’re using in this tute?

    Let’s say I posted 3 times on May 2nd, and another 3 times on May 1st. Currently, this is what what the main page will look like:
    May 2nd—
    Post id 6, Cat id 1
    Post id 5, Cat id 3
    Post id 4, Cat id 2

    May 1st—
    Post id 3, Cat id 2
    Post id 2, Cat id 1
    Post id 1, Cat id 3

    But here’s what I’d like to see:
    May 2nd—
    Post id 6, Cat id 1
    Post id 4, Cat id 2
    Post id 5, Cat id 3

    May 1st—
    Post id 2, Cat id 1
    Post id 3, Cat id 2
    Post id 1, Cat id 3

    Is something like that even possible?

  • tommy

    @Jim

    I’m not sure if there’s an easy way in WP to find the previous and next dates on which posts exist, so you’d have to do it in raw PHP, consecutively querying each day/week/month/whatever, then you’d apply this code/logic to get those results sorted by category.

    Again, there might be a better way! I’m all ears to anyone with any ideas.

  • http://studioholling.com/ holling

    Wondering if there is some hack that could be used to sort the subcategories. ID is not ideal, ‘categtory’ would theoretically sort by cat name, but according to everyone that is broken and not likely to be fixed. Ideal for me would be the slug…any thoughts?

    Thanks for the tutorial…awesome!

    h

  • tommy

    Hey, glad you liked the tutorial!

    Not sure I understand your question, though… Do you mean you’d like to still sort a category’s subcategories as I had explained, then additionally sort their respective posts by slug?

    If that’s the case, you can order by ID by adding the correct parameter to the script’s query_posts function:
    http://codex.wordpress.org/Template_Tags/query_posts#Orderby_Parameters

  • http://studioholling.com/ holling

    Hi Tommy –

    Thanks for the response. To clarify, the site is a recipe site that publishes a new set of recipes each Monday. Our choice for the archives of recipes is to organize them by week. So, I have a cat called ‘Recipes by Week’ and subcats for each Monday (June 22, June 15, June 8, …). The issue is that they are needed to create categories moving forward as the weeks progress, but also backwards (archiving their old recipes into weeks, scraped from their old site).

    If they weren’t going backward, the best bet would be to go with ID, but that will produce wonky behavior as IDs are added, and their weeks will not correspond to their incrementing IDs.

    My hope was that I could sort on category slug–I’ve named the weeks in YYYYMMDD format, giving me absolute sorting ability across years, but it appears that WP doesn’t allow for sorting on that bit of data.

    BTW, the site is: http://www.meatlessmonday.com/ and the recipe archive is (from the left nav): http://www.meatlessmonday.com/category/recipes-by-week/

    Cheers –

    Bob

    ps. within each category, I’m sorting using the Postmash plugin order for more control.

  • tommy

    Oh, I see!

    You could rename your subcategories with the YYYMMDD at the beginning and everything will sort itself out alphanumerically, giving you the order you’d want. If the new titles are too unsightly, you could try replacing the category’s titles with their descriptions (just make them whatever their normal title would be) within the loop.

    Alternatively, I think, if you wanted to get your hands more grubby, you could try rearranging the PHP array we got from get_categories(). Haven’t tried it and not 100% sure how well it would work, but it might be a good experiment!

    Hope that helps, thanks for reading, and good work with that site! Looks real nice!

  • ann

    Thanks, great, that’s exactly what I was looking for. Just one question, is ist possible to start a new array after the div-tag “genre_subcat”?
    … Let’s say: The categories and posts are organized as followed: Music -> Rock -> Australian -> “The History of AC/DC”
    So that the subcat Rock has its own subcat Australian.

  • tommy

    @ann

    It would get confusing pretty fast, but I don’t see why you couldn’t do that. I’ll leave it up to you to write the code.

    After you’ve pulled in the child categories (Line 1) and are going through them with “for each”, pull in each consecutive subcat’s subsubcat’s with the same code, switching out the variables so they don’t overwrite.

    If you could wrap your head around it, you could probably write some logic that checks each cat for subcats and automatically pulls out the whole tree, as deep as is needed in the hierarchy, maybe set by a variable. Hell, put the whole thing in a function.

    Hope that helps!

  • ann

    Thanks, that helps quite a lot.

    But you are right, it is a bit confusing. Anyway, I am the only one to blame for. I shouldn’t have organized my posts by subsubcats. It is just a whole mess.

    Thanks for the ideas you are sharing.
    Ann

  • Marie

    Thank you so SO much for this. I needed to do exactly this. but couldn’t figure out for the life of me how to do it. I was mentally rehearsing the speech I was going to give to my client to explain why I was going to miss my deadline when I found this. Speech abandoned, problem solved.

    Thanks again!

  • Pedro Oliveira

    Thank you so much for this, it works perfectly… BUT, I have a question… I don’t know if it is dummy, but I can’t figure it out by myself…

    I have two “classes” of categories in my theme… and I want to do this sort, but only show the posts included in other class as well. For instance:

    I have two parent categories: “Projects” and “Levels”. I have a bunch of posts which are associated with one Project but also with many Levels. I want that, when viewing a Project page (meaning the category page of the project), it organizes the content by the categories that are children of “Levels”. So, it will only show the children of Levels that are associated with an specific Project. Did I make myself clear enough?

    Any help would be appreciated!

  • Pedro Oliveira

    Ok, already figured it out using “category__and” syntax. If anyone is interested I can post how I did it :)

  • http://mysqltalk.wordpress.com/ Joe Devon

    It’s amazing that there are subcategories in WordPress yet no easy way to organize them intuitively.

    Thanks for your code. If I understand properly from the WordPress Codex’s explanation of query_posts, it sounds like a new database query is being generated each time it’s called. So by wrapping it in a foreach loop, you have n queries on that page. If there are only a couple subcategories, not necessarily a big deal. But for sites with a ton of subcategories, this could be an issue.

  • http://ashhaque.com Ash Haque

    Exactly what I was looking for! Cheers

  • Hélène

    Works Great ! Thank you !

  • http://fearlessflyer.com Michael Soriano

    works as described! check out what i did with your code: http://jakesrh.net/category/2lunch-and-dinner/

    thanks again!

  • http://www.mfinleydesigns.com/ Morgan Finley

    I used this code to do the same thing as Michael. My usage is exactly the same, only I’m listing products, rather than menu items split into different meals. Like Michael, I removed the category descriptions, posts and meta— and voila, a list of products by category.

    To make the subcategory headings (line 4) into live links I changed the code to:

    <a href="cat_ID);?>”>

  • http://www.mfinleydesigns.com Morgan Finley

    Sorry, code got butchered in my last post. I changed line 4 to the following:

    <a href="cat_ID);?>”>

  • kca

    Hello,

    I just have a question, if you don’t mind of course ^o^:
    How can I list the subcategory by ID and not by A…, B, C,….?

    Thanks for your work.

  • kca

    Sorry for my stupid question :( I got it:

    get_categories(“child_of=17&orderby=ID”);

    :)

  • Gabe

    I may adopt my strategy using the code you’ve explained so well, but…
    I’ve been trying to sort a particularly category (as you’ve done), but showing posts in that category grouped by author.

    Any ideas or pointers?

    TIA

  • http://www.johncrumpton.com John Crumpton

    There is a plugin that sorts categories by subject and is collapsible. http://blog.robfelty.com/plugins/collapsing-categories/

  • kca

    Hello, it s me again ^^

    Do you have any idea how i can use you code but listing the post by name without messing with the loop?

    Thanks again for your help.

  • tommy
  • kca

    Yeah thanks Tommy, in fact I get confuse because of my cache ^o^

  • http://www.toobler.com Ajith

    Wow..Excellent Tommy.This what I am looking for more hours…

  • http://bespy.be Invawnnup

    Hello
    Spy cameras are used for offices and home.
    [URL=http://www.bespy.be/Key-Cam-recorder.html]Spy cam recorder[/URL] is best to record Audio and Video
    [url=http://www.bespy.be/Video-Audio-recorders][img]http://www.bespy.be/images/T/BSDVR011%20.jpg[/img][/url]
    You can see many spy camera designs in online store
    Have a Fantastic day

  • Maurizio

    Thank you, exactly what I was looking for. I, too, as Morgan Finley (comment #18), needed the subcategory headings to work as links. Unfortunately I couldn’t make his snippet work. The solution I found is: <a href="cat_ID) ?>">

  • Maurizio

    Ops.. Also my code got butchered. Anyway, use echo get_category_link($cat->cat_ID) (inside php tags) as destination for the href attribute.

  • http://www.sherodesigns.com Beth

    Hi this has been a major savior! Question I am a beginner at PHP how can I add pagination to this?

  • Pingback: 10 Awesome WordPress hacks to enhance your blog’s usability | Web Design & Development Blog

  • Pingback: Plasterdog – Wordpress Instructions » Clear navigation from categeory to sub-category

  • Kathy

    This is awesome. Thanks so much for sharing!

  • Naoshad Nayeem

    gr8 post. very helpful. thanks.. :)

  • http://www.facebook.com/profile.php?id=100002414771667&v=info daniel mamann puerto vallarta

    Hi there this is somewhat of off topic but I was wondering if blogs use WYSIWYG editors or if you have to manually code with HTML. I’m starting a blog soon but have no coding know-how so I wanted to get guidance from someone with experience. Any help would be greatly appreciated!

  • Pingback: 10 Enhancements for WordPress

  • http://www.pushpinderbagga.com/ Pushpinder Bagga

    Just what I wanted. Thanks a lot mate!

  • newage

    This is great code! The only issue for me is that it shows every post on one page (could be an issue if you have over 100 posts). Can anyone suggest how to add code to it to limit the number of posts per page?

  • http://dabbledstudios.com dot

    Thanks so much for this! it was exactly what i needed! I used a variant of it here: http://talkoftomatoes.com on the recipe index and archives pages.

  • http://www.jimmychooshoesusa.com/ BeapReibrip

    the company Chairman Xia Li shared with reporter, Morita based Henan farming large province resources edge, To support the building of economic zone of the Central Plains of that State Council for opportunity, leading enterprises in agricultural industrialization leading role directly into full play, open up the market with brand, to market-led [url=http://www.jimmychooshoesusa.com/]cheap jimmy choo[/url] group regarding Henan local accumulation connected with advantageous agricultural industry exhibition base, flourishing agriculture is fitting in with build China’s Souvenirs Item leading brand. From the famous all 5 famous hometown Henan Jintang kiln Jun kiln Jun kiln commences China prosperous times Dragon your Dragon new year works the drums, attract many people’s face, For this forum demonstrate a thick Central Plains culture and a crucial attraction in Henan economy image.

    main funds inflow a new unit (one-eleventh) plenty of unit cut meat fled certainly regret burst soaring is may won’t period and to shareholders Gospel: stuck stock saved provides! County financial services “not impressive” over the years, the County Jimmy Choo Bags Replica to be a main carrier of bearing capacity from the national population and economies of scale, always [url=http://www.jimmychooshoesusa.com/]jimmy choo outlet[/url] maintain a fast development Jimmy Choo Bags Replica within the great development of the particular economic and social circumstance. Statistics, the country has your population of 70% residing from the County, County economy in amount of total national GDP has greater than 50%, tangible evidence that your pattern of County economy in China’s economic gardening and plays an increasingly part.

    Today, Pearl River beer (hereinafter referred to as Pearl beer) discover, in order to accomplish corporate headquarters relocation and also rational distribution of manufacturing capacity, while a technology improvement and adjustment of supplement structure, the company intends to no less than $ 10. 37/unit price, not more than Furla Carriers 215 million private position shares, raise 2. 213 billion yuan expansion capacity.Pearl [url=http://www.jimmychooshoesusa.com/]jimmy choo shoes sale[/url] River Furla Hand bags beer capital increase power expansion capital funds directly into stocks (one-eleventh) ran away some unit reduce meat certainly regret sudden boom is not really likely in a step investors Gospel: hold stocks saved! Notice display, Nansha Pearl beer II period of time construction project completed Hou, company headquarters capacity may overall relocation.

    Read More:
    [url=http://www.jimmychooshoesusa.com/] http://www.jimmychooshoesusa.com/ [/url]

  • http://www.merlinmason.co.uk Merlin Mason

    Aha, this is just what I was looking for to organise the sub-categories of products!
    Thanks a lot for sharing :)

  • stackflow

    Not working on WordPress 3.3, any ideas?

  • Pingback: The Best Of WordPress Snippets - Part 3 - JustWP.org

  • Pingback: The BestOf WordPress Snippets Part – 5 - JustWP.org