Hierarchical Category List with Post Titles

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

Highlight the post’s categories in the category list

highlighting the categories of a post in single post view is a useful trick to allow the viewer to find related posts.

there are plugins available which extend the functionality of the standard category widget to do this.

sometimes, however, it can be desirable to have the same feature with a function that you can use like you would use ‘wp_list_categories();’ – exactly with the same arguments.

/* hi_list_categories() to highlight the current categories of a post in single.php;
uses the arguments in the same way as wp_list_categories();
alchymyth 2010 / www.transformationpowertools.com/wordpress */
function hi_list_categories($args) {
//following section is extracted from http://phpxref.com/xref/wordpress/wp-includes/category-template.php.source.html#l389
$defaults = array(
'show_option_all' => '',
'orderby' => 'name',
'order' => 'ASC',
'show_last_update' => 0,
'style' => 'list',
'show_count' => 0,
'hide_empty' => 1,
'use_desc_for_title' => 1,
'child_of' => 0,
'feed' => '',
'feed_type' => '',
'feed_image' => '',
'exclude' => '',
'exclude_tree' => '',
'current_category' => 0,
'hierarchical' => true,
'title_li' => __( 'Categories' ),
'echo' => 1,
'depth' => 0
);
$r = wp_parse_args( $args, $defaults );
if ( !isset( $r['pad_counts'] ) && $r['show_count'] && $r['hierarchical'] ) {
$r['pad_counts'] = true;
}
if ( isset( $r['show_date'] ) ) {
$r['include_last_update_time'] = $r['show_date'];
}
if ( isset( $r['echo'] ) ) {
$echo_or_return = $r['echo'];
} ; $r['echo'] = 0;
if ( true == $r['hierarchical'] ) {
$r['exclude_tree'] = $r['exclude'];
$r['exclude'] = '';
}
extract( $r );
//end of extracted code
global $post;
// highlighting only for single post view
if(is_single()) :
$categories = wp_get_post_categories($post->ID);
foreach ($categories as $catid) {
$cat = get_category($catid);
$cats[] = $cat->cat_ID;
}
$cats_list = wp_list_categories( $r );
foreach($cats as $value) {
if(preg_match('#-item-' . $value . '">#', $cats_list)) {
$cats_list = str_replace('item-' . $value . '">', 'item-' . $value . ' current-cat">', $cats_list);
}
}
if($echo_or_return == 1) { echo $cats_list; }
else { return $cats_list; } ;
else :
//use default category list if not single post view
wp_list_categories( $args );
endif;
} //end of function hi_list_categories();

in the same way, as you would have used ‘wp_list_categories();’ you can now use ‘hi_list_categories();’ which will add the class ‘.current-cat’ to each of the categories of the post in single post view.