If your wordpress site is organized with categories, it might be very useful to have a template to show an organized list of all categories with the associated posts.
This would work similar to the category widget with the setting ‘hierarchical’ – only that for each category, all the post titles are listed with links to the individual post.
This is the code:
<?php
/*****************************************************************
*
* alchymyth 2011
* a hierarchical list of all categories, with linked post titles
*
******************************************************************/
// http://codex.wordpress.org/Function_Reference/get_categories
foreach( get_categories('hide_empty=0') as $cat ) :
if( !$cat->parent ) {
echo '<ul><li><strong>' . $cat->name . '</strong></li>';
process_cat_tree( $cat->term_id );
}
endforeach;
wp_reset_query(); //to reset all trouble done to the original query
//
function process_cat_tree( $cat ) {
$args = array('category__in' => array( $cat ), 'numberposts' => -1);
$cat_posts = get_posts( $args );
if( $cat_posts ) :
foreach( $cat_posts as $post ) :
echo '<li>';
echo '<a href="' . get_permalink( $post->ID ) . '">' . $post->post_title . '</a>';
echo '</li>';
endforeach;
endif;
$next = get_categories('hide_empty=0&parent=' . $cat);
if( $next ) :
foreach( $next as $cat ) :
echo '<ul><li><strong>' . $cat->name . '</strong></li>';
process_cat_tree( $cat->term_id );
endforeach;
endif;
echo '</ul>';
}
?>
The first step is to find all top level categories (generated in alphabetical order) – which is simply done with the wordpress function ‘get_categories()’ and by checking if the category has a parent.
Caveat: because the code is checking for top level categories only, you can’t directly use the parameters of ‘get_categories()’ (see the Codex, the mostly unread documentation of WordPress) without some customization of the top section of the code.
The second step is to show the titles of all available posts for each top level category, linked to the full individual post; done with ‘get_posts()’ and ‘get_permalink()’.
The third step is to find possible direct child categories for this (top) category; done with the ‘parent’ parameter of ‘get_categories()’.
Then step 2 and 3 are repeated until all possible categories are dealt with.
edit 11/06/2011: parameter corrected.
edit 10/02/2012: a slightly different code – without the post lists – for a nested hierarchical category list with links to the category archive and an edit link for the category: http://pastebin.com/TTvYPKPH – initiated by this WPSE question

The more birds that you have the higher chance the plant destroy pests will be eaten by
the birds. These scouts would leave behind some scent trail that would
enable them to come back to their colony carrying the good news regarding their discovery of resources.
Knowing your pest is essential for identifying the appropriate treatment protocol, and many do-it-yourself pond managers have spent
valuable time and money on unsuccessful strategies.
Feel free to surf to my web blog: http://basicpestcontrolsoftware.wordpress.com
thank you so much for a very good piece of code.
I am using the code mixed with various other people in the thread to create accordion category menu with posts. Now I want to use the same code where I do not want to display the posts but have link to the category page.
WHAT I HAVE RIGHT NOW
category 1
subcat1
post1
post2
subcat2
category2
WHAT I WANT
category 1
subcat1
subcat2
category2
THE CODE I AM USING IS
<?php
foreach( get_categories('hide_empty=0&include=8') as $cat ) :
if( !$cat->parent ) {
echo '<ul id="nav-side">';
process_cat_tree( $cat->term_id );
}
endforeach;
wp_reset_query(); //to reset all trouble done to the original query//
function process_cat_tree( $cat) {
$args = array('category__in' => array( $cat ), 'numberposts' => -1);
$cat_posts = get_posts( $args );
global $post;
if( $cat_posts ) :
foreach( $cat_posts as $menuPost ) :
echo '<li class="child';
if ( $menuPost->ID == $post->ID ) { echo ' current'; }
echo '">';
echo '<a href="' . get_permalink( $menuPost->ID ) . '">' . $menuPost->post_title . '</a>';
echo '</li>';
endforeach;
endif;
$next = get_categories('hide_empty=0&orderby=id&order=DESC&parent=' . $cat);
$post_cats = array(); foreach(get_the_category($post->ID) as $post_cat) $post_cats[] = $post_cat->term_id;
if( $next ) :
foreach( $next as $cat ) :
echo '<li' . (in_array($cat->term_id,$post_cats)?' class="active"':'') . '>';
echo '<a href="' . get_category_link( $cat) . '">' . $cat->name . '</a>';
echo '<ul class="sub-menu">';
process_cat_tree( $cat->term_id );
endforeach;
endif;
echo '</ul>
</li>';
}
?>
DID FOLLOWING
<?php
foreach( get_categories('hide_empty=0&include=8') as $cat ) :
if( !$cat->parent ) {
echo '<ul id="nav-side">';
process_cat_tree( $cat->term_id );
}
endforeach;
wp_reset_query(); //to reset all trouble done to the original query//
function process_cat_tree( $cat) {
$next = get_categories('hide_empty=0&orderby=id&order=DESC&parent=' . $cat);
$post_cats = array(); foreach(get_the_category($post->ID) as $post_cat) $post_cats[] = $post_cat->term_id;
if( $next ) :
foreach( $next as $cat ) :
echo '<li' . (in_array($cat->term_id,$post_cats)?' class="active"':'') . '>';
echo '<a href="' . get_category_link( $cat) . '">' . $cat->name . '</a>';
echo '<ul class="sub-menu">';
process_cat_tree( $cat->term_id );
endforeach;
endif;
echo '</ul>
</li>';
}
?>
ITS SHOWING ONLY CATEGORIES BUT THE LINKS DO NOT WORK….
echo '<a href="' . get_category_link( $cat->term_id) . '">' . $cat->name . '</a>';Ok I fixed it by doing following. it is giving me active state on the “SUBCAT1″ now I want the active state for “Category1″ also for the following .
Category 1(still needed)
subcat1(got active)
post
post(active)
subcat2
<?php
foreach( get_categories('hide_empty=0&include=4') as $cat ) :
if( !$cat->parent ) {
echo '<ul id="nav-side">';
process_cat_tree( $cat->term_id );
}
endforeach;
wp_reset_query(); //to reset all trouble done to the original query
//
function process_cat_tree( $cat) {
$args = array('category__in' => array( $cat ), 'numberposts' => -1);
$cat_posts = get_posts( $args );
global $post;
if( $cat_posts ) :
foreach( $cat_posts as $menuPost ) :
echo '<li class="child';
if ( $menuPost->ID == $post->ID ) { echo ' current'; }
echo '">';
echo '<a href="' . get_permalink( $menuPost->ID ) . '">' . $menuPost->post_title . '</a>';
echo '</li>';
endforeach;
endif;
$next = get_categories('hide_empty=0&orderby=id&order=DESC&parent=' . $cat);
if(is_single()) { $post_cats = array(); foreach(get_the_category($post->ID) as $post_cat) { $post_cats[] = $post_cat->term_id; } };
if( $next ) :
foreach( $next as $cat ) :
echo '<li' . ((is_single()&&in_array($cat->term_id,$post_cats))?' class="active"':'') . '>
<a href="#">' . $cat->name . '</a>
<ul class="sub-menu">';
process_cat_tree( $cat->term_id );
endforeach;
endif;
echo '</ul></li>';
}
?>
you possibly need to add any ancestors of each post’s category into the array which is generated here:
foreach(get_the_category($post->ID) as $post_cat) { $post_cats[] = $post_cat->term_id; }try to work with
get_ancestors()http://codex.wordpress.org/Function_Reference/get_ancestorsI did
$post_cats = array(); foreach(get_ancestors($post->ID) as $post_cat) $post_cats[] = $post_cat->term_id;but doesnt do anyhting.it takes out the parent category active state.
Please help
Thnak you for the quick response but the solution didnt work. It may be that i dint know how to do it. I am not good at php…just started learning….
following is how I added ur code
<?php
if(is_single()) { $post_cats = array(); foreach(get_the_categories($post->ID) as $post_cat) { $post_cats[] = $post_cat->term_id; } };
foreach( get_categories('hide_empty=0&include=4') as $cat ) :
if( !$cat->parent ) {
echo '<ul id="nav-side">';
process_cat_tree( $cat->term_id );
}
endforeach;
wp_reset_query(); //to reset all trouble done to the original query
//
function process_cat_tree( $cat) {
$args = array('category__in' => array( $cat ), 'numberposts' => -1);
$cat_posts = get_posts( $args );
global $post;
if( $cat_posts ) :
foreach( $cat_posts as $menuPost ) :
echo '<li class="child';
if ( $menuPost->ID == $post->ID ) { echo ' current'; }
echo '">';
echo '<a href="' . get_permalink( $menuPost->ID ) . '">' . $menuPost->post_title . '</a>';
echo '</li>';
endforeach;
endif;
$next = get_categories('hide_empty=0&orderby=id&order=DESC&parent=' . $cat);
if( $next ) :
foreach( $next as $cat ) :
echo '<li' . ((is_single()&&in_array($cat->term_id,$post_cats))?' class="active"':'') . '>
<a href="#">' . $cat->name . '</a><ul class="sub-menu">';
process_cat_tree( $cat->term_id );
endforeach;
endif;
echo '</ul></li>';
}
?>
but i get the following error
sleepers & i at bay
watercolor on paper, 5″ x 7″
Fatal error: Call to undefined function get_the_categories() in /home/raju/public_html/project/cutetastrophe/wp-content/themes/cutetastrophe/sidebar-artplay.php on line 30
my mistake – the function is properly called
get_the_category();i.e. change the one line to:
if(is_single()) { $post_cats = array(); foreach(get_the_category($post->ID) as $post_cat) { $post_cats[] = $post_cat->term_id; } };http://codex.wordpress.org/Function_Reference/get_the_category
Again an error
Warning: in_array() [function.in-array]: Wrong datatype for second argument in /home/raju/public_html/project/cutetastrophe/wp-content/themes/cutetastrophe/sidebar-artplay.php on line 56
2009
I added ur code as follows
<?php if(is_single()) { $post_cats = array(); foreach(get_categories($post->ID) as $post_cat) { $post_cats[] = $post_cat->term_id; } }; ?>
<?php
foreach( get_categories('hide_empty=0&include=4') as $cat ) :
if( !$cat->parent ) {
echo '<ul id="nav-side">';
process_cat_tree( $cat->term_id );
}
endforeach;
wp_reset_query(); //to reset all trouble done to the original query
//
function process_cat_tree( $cat) {
$args = array('category__in' => array( $cat ), 'numberposts' => -1);
$cat_posts = get_posts( $args );
global $post;
if( $cat_posts ) :
foreach( $cat_posts as $menuPost ) :
echo '<li class="child';
if ( $menuPost->ID == $post->ID ) { echo ' current'; }
echo '">';
echo '<a href="' . get_permalink( $menuPost->ID ) . '">' . $menuPost->post_title . '</a>';
echo '</li>';
endforeach;
endif;
$next = get_categories('hide_empty=0&orderby=id&order=DESC&parent=' . $cat);
if( $next ) :
foreach( $next as $cat ) :
echo '<li' . ((is_single()&&in_array($cat->term_id,$post_cats))?' class="active"':'') . '>
<a href="#">' . $cat->name . '</a><ul class="sub-menu">';
process_cat_tree( $cat->term_id );
endforeach;
endif;
echo '</ul></li>';
}
?>
but gives me an error
Warning: in_array() [function.in-array]: Wrong datatype for second argument
Pingback: Displaying Custom Post Types by Term | iNexi
April 2, 2012 | [...] This goal led me to what is probably a cleaner solution. The following code is adapted from Hierarchical Category List …
I am so glad I found your site and words of wisdom – I am a keen fan of your postings on wordpress.org site. this code above is exactly what I am looking for. I am making a child theme from TwentyEleven and pasted this into a page template file – is this where it should go or should I put it somewhere else.
I want to show all child categories of ‘current vendors’(parent category) and their post titles only and NOT all categories. It works as I have it in this example but I am having to set div #vendors display none in style sheet. I know this is bad but it’s working – please advise.
<div id="primary">
<div id="content" role="main">
<div class="vendors"><?php
/*****************************************************************
*
* alchymyth 2011
* a hierarchical list of all categories, with linked post titles
*
******************************************************************/
// http://codex.wordpress.org/Function_Reference/get_categories
foreach( get_categories('hide_empty=0') as $cat ) :
if( !$cat->parent ) {
echo '<ul><li><strong>' . $cat->name . '</strong></li>';
process_cat_tree( $cat->term_id );
}
endforeach;
wp_reset_query(); //to reset all trouble done to the original query
//
function process_cat_tree( $cat ) {
$args = array('category__in' => array( $cat ), 'numberposts' => -1);
$cat_posts = get_posts( $args );
if( $cat_posts ) :
foreach( $cat_posts as $post ) :
echo '<li>';
echo '<a href="' . get_permalink( $post->ID ) . '">' . $post->post_title . '</a>';
echo '</li>';
endforeach;
endif;
$next = get_categories('hide_empty=0&parent=' . $cat);
if( $next ) :
foreach( $next as $cat ) :
echo '<ul><li><strong>' . $cat->name . '</strong></li>';
process_cat_tree( $cat->term_id );
endforeach;
endif;
echo '</ul>';
}
?></div>
<?php // http://codex.wordpress.org/Function_Reference/get_term_by
$cat = get_category(get_term_by('slug','current-vendors','category'));
echo '<ul class="vendor_grid"><li><strong>' . $cat->name . '</strong></li>';
process_cat_tree( $cat->term_id );?>
</div><!-- #content -->
</div><!-- #primary -->
Thank you for all the advice you have posted on wordpress.org
Hello Alchymyth,
Your site has helped me a lot, and I’m glad I was able to find you. It’s really nice to see someone helping others in this way. In your caveat beneath the code example you say that you can’t directly use the parameters of get_categories… This leads to my question.
How would one go about displaying the category description for ALL categories in the list, directly beneath each category listing (before the list of individual posts).
I hope you have the time to respond, if not, again, I fully appreciate the time you’ve spent on your site.
I believe this worked… tell me if I’m right?
<?php
foreach( get_categories('hide_empty=0') as $cat ) :
if( !$cat->parent ) {
echo '<ul><li><strong>' . $cat->name . '</strong></li>';
echo '<div class="cat-desc"><p>' . $cat->category_description . '</p></div>';
process_cat_tree( $cat->term_id );
}
endforeach;
Hi alchymyth . Thank you for this tutorial. I’ve used it with two changes – I copy-pasted your recent comment to show only categories/posts within my category ‘Topics’, and I replaced ‘strong’ with ‘a href=”#” class=”level1″‘ to add a bit of styling to the menu.
Please see http://samanthazalaznick.com – The top menu of links is the menu generated by your code. Below that, seperated by the big pink line, is static html with how I want the final menu to look and function. There is different styling applied to different level ul’s and li’s and I’m not sure how to modify your code to get that effect. I was easily able to apply “level1″ to all the child categories but I don’t know how to increment that for the deeper subcategories. I imagine I need to have a variable that increments to make it go level1, level2, etc. but don’t know how to achieve that. I also want to apply a certain class to top-level ul’s (“menu noaccordion”) and then a different class to all subcategory ul’s (“noaccordion acitem indent”). The reason for the different classes is for the particular javascript I’m using to make the menus expandable.
Otherwise your code has gotten me close to where I need to be. If you can help me in any way I would really appreciate it, let me know if you need more information on my site. Thank you!
Hi Chris,
I am going to look into this in the next few days, and let you know how difficult this might be.
Great article!I’m new to WordPress and have been tnyirg to figure out all that needs to be blocked or modified so I don’t have dup content this article actaully makes categories useful!! Gives me more pages in googles index, thanks.Now, what about tags?I haven’t yet found everything on your site, if you have a good article on making the tag usefule i.e. like you did with categories because doesn’t google also see tags the same way?If I have a tag, let us say widgets, then that will have duplicate content because every post about widgets will have a short summary and it doesn’t do much for optimizing that tag now does it.Haven’t seen anything on this Would love to hear your thoughts.Thanks,Charles
I have been searching all over for something like this. Thank you! Works great!
I do have a question though, how can one specify to only display posts and category titles from a specific category?
For example: I have a category Past exhibitions, with sub-categories below that. I only want to display the category names and post titles from Past exhibitions and none of my other categories.
try:
// http://codex.wordpress.org/Function_Reference/get_term_by
$cat = get_category(get_term_by('slug','past-exhibitions','category'));
echo '<ul><li><strong>' . $cat->name . '</strong></li>';
process_cat_tree( $cat->term_id );
Thank you! That worked great!
Hello, very nice solution.
I’m looking for something similar but with a specific taxonomy for a specific custom post type.
Do you think your code is a good starting point to get what i need?
I really want to use this code but have limited knowledge of WordPress. Should this code be added to any existing php file or saved as a separate file under twentyeleven theme?
Regards
Ann
the code would probably need to be added as part of a page template.
for general assistance with wordpress, i suggest that you join the wordpress.org support forum, and ask any open questions there.
good luck.
Thank you alchymyth! I just wonder if there is a way to show posts only from child categories? Now it is duplicating post titles.
Thank you again for sharing this.
at the moment, with ‘category__in’ in the arguments for get_posts(), the code already only gets posts which are directly in a category, not posts of the child categories of that category.
i assume that your posts are in more than one category – one of which is the parent of the other – and that this is the reason for duplicate posts.
duplicates are not filtered on purpose, to show the relationship between all posts and the categories; i.e. if a post has more than one category ticked, it will show more than once in the list.
to answer your question ‘if there is a way to show posts only from child categories?’, one would need to know how your posts and categories are structured, and my direct answer is: ‘i just don’t know right now’.
Brilliant! This saved my day!
Made one amendment to the “if ( $cat_posts )” section:
global $post;if( $cat_posts ) :
echo '<ul class="menuposts">';
foreach( $cat_posts as $menuPost ) :
echo '<li class="child';
if ( $menuPost->ID == $post->ID ) { echo ' current'; }
echo '">';
echo '<a href="' . get_permalink( $menuPost->ID ) . '">' . $menuPost->post_title . '</a>';
echo '</li>';
endforeach;
echo '</ul>';
endif;
Which identifies the active link(s) for styling.
Wonder this functionality isn’t included in the standard WP package…
I am using the code for multilevel accordion menu with category posts. With your method, I got the active state on the posts how can i get the active state for parent menu. For example,
Category 1
subcat1
post
post(active)
subcat2
In the above list, when the post is active, I want the subcat1 and Category1also be active.
I have the following code.
<?php
foreach( get_categories('hide_empty=0&include=6') as $cat ) :
if( !$cat->parent ) {
echo '<ul id="nav-side">';
process_cat_tree( $cat->term_id );
}
endforeach;
wp_reset_query(); //to reset all trouble done to the original query
//
function process_cat_tree( $cat) {
$args = array('category__in' => array( $cat ), 'numberposts' => -1);
$cat_posts = get_posts( $args );
global $post;
if( $cat_posts ) :
foreach( $cat_posts as $menuPost ) :
echo '<li class="child';
if ( $menuPost->ID == $post->ID ) { echo ' current'; }
echo '">';
echo '<a href="' . get_permalink( $menuPost->ID ) . '">' . $menuPost->post_title . '</a>';
echo '</li>';
endforeach;
endif;
$next = get_categories('hide_empty=0&orderby=id&order=DESC&parent=' . $cat);
if( $next ) :
foreach( $next as $cat ) :
echo '
<li>
<a href="#">' . $cat->name . '</a><ul class="sub-menu">';
process_cat_tree( $cat->term_id );
endforeach;
endif;
echo '</ul></li>';
}
?>
untested – possibly get the post’s categories before that code, something like
<?php if(is_single()) { $post_cats = array(); foreach(get_the_categories($post->ID) as $post_cat) { $post_cats[] = $post_cat->term_id; } }; ?>then compare this array with whatever category is just output by the code;
example:
echo '<li' . ((is_single()&&in_array($cat->term_id,$post_cats))?' class="active"':'') . '>
<a href="#">' . $cat->name . '</a><ul class="sub-menu">';