4
votes

Im trying to display a list of my wordpress categories with nested subcategories. So far i've only been able to get a list of parent categories or a list of subcategories excluding parents but I haven't been able to join the two together.

This is the sort of result I am looking to create:

  • Parent Category
    • Subcategory
    • Subcategory
  • Parent Category
    • Subcategory
  • Parent Category
    • Subcategory
    • Subcategory
    • Subcategory

EDIT:

The idea for this is to create a custom category page. The HTML is as follows:

<h1>Categories</h1>
<ul class="blocks">
    <li>
        <img src="http://placehold.it/250x250" alt="title" />
        <h2>Parent Category</h2>
        <ul class="models">
            <li><a href="#">Sub Category</a></li>
            <li><a href="#">Sub Category</a></li>
        </ul>
    </li>
    <li>
        <img src="http://placehold.it/250x250" alt="title" />
        <h2>Parent Category</h2>
        <ul class="models">
            <li><a href="#">Sub Category</a></li>
            <li><a href="#">Sub Category</a></li>
            <li><a href="#">Sub Category</a></li>
        </ul>
    </li>
</ul>
3
What are you using to output the categories? wp_list_categories() ?pmandell
Hi @pmandell, I was but due to the HTML above I can't use the 'hierarchical' property.Oliver Evans

3 Answers

7
votes

You can use wp_list_categories() function which uses these defaults:

<?php wp_list_categories(array(
    'show_option_all'    => '',
    'orderby'            => 'name',
    'order'              => 'ASC',
    'style'              => 'list',
    'show_count'         => 0,
    'hide_empty'         => 1,
    'use_desc_for_title' => 1,
    'child_of'           => 0,
    'feed'               => '',
    'feed_type'          => '',
    'feed_image'         => '',
    'exclude'            => '',
    'exclude_tree'       => '',
    'include'            => '',
    'hierarchical'       => 1,
    'title_li'           => __( 'Categories' ),
    'show_option_none'   => __( 'No categories' ),
    'number'             => null,
    'echo'               => 1,
    'depth'              => 0,
    'current_category'   => 0,
    'pad_counts'         => 0,
    'taxonomy'           => 'category',
    'walker'             => null
)); ?>

So technically you can just say:

wp_list_categories();

And this will list your categories hierarchically hiding any empty categories and adding a title of "Categories" above them all.

EDIT - Separate Parents and Children

You can try something like this, this using a combination of both wp_list_categories() and the get_categories() function.

<h1>Categories</h1>
<ul class="blocks">
<?php $parents = get_categories(array('hierarchical' => false));
    if(!empty($parents)){
        foreach($parents as $parent){
?>
        <li>
            <h2><?php echo $parent->name; ?></h2>
            <ul class="models">
                <?php wp_list_categories(array('hierarchical' => false, 'child_of' => $parent->term_id)); ?>
            </ul>
        </li>
<?php
        }
    } else { 
?>
    <li>No Categories</li>
<?php } ?>
</ul>
1
votes

For those finding this all this time later, here is an example of this I created recently using get_categories() and foreach loops at each level to get child categories that have the current level categories as parents. It goes three levels deep, but can easily be modified to go deeper or shallower.

I've kept my own use case's HTML in here instead of using the code from the original question, but that too can be easily modified in the template part. This particular chunk of code builds the nested list of categories with checkbox inputs and labels in the list.

<?php
$parent_cats = get_categories(array('parent' => 0));
?>
<?php if( ! empty( $parent_cats ) ) :

    foreach( $parent_cats as $parent_cat ) :
        $child_cats = get_categories(array('parent' => $parent_cat->term_id));
?>

    <li>

        <label for="<?php echo $parent_cat->slug; ?>">

            <input type="checkbox" name="cat" id="<?php echo $parent_cat->slug; ?>">
            
            <?php echo $parent_cat->name; ?>

        </label>

        <?php if( $child_cats ) : ?>

            <ul class="child-cats">

                <?php foreach( $child_cats as $child_cat ) :
                    $grandchild_cats = get_categories(array('parent' => $child_cat->term_id));
                ?>

                    <li>

                        <label for="<?php echo $child_cat->slug; ?>">

                            <input type="checkbox" id="<?php echo $child_cat->slug; ?>" name="cat">

                            <?php echo $child_cat->name; ?>
                            
                        </label>
                        
                        <?php if( $grandchild_cats ) : ?>

                            <ul class="grandchild-cats">

                                <?php foreach( $grandchild_cats as $grandchild_cat ) : ?>

                                    <li>

                                        <label for="<?php echo $grandchild_cat->slug; ?>">

                                            <input type="checkbox" id="<?php echo $grandchild_cat; ?>" name="cat">

                                            <?php echo $grandchild_cat->name; ?>
                                            
                                        </label>
                                        
                                    </li>

                                <?php endforeach; ?>
                                
                            </ul>

                        <?php endif; ?>

                    </li>

                <?php endforeach; ?>
                
            </ul>

        <?php endif; ?>

    </li>

<?php endforeach; endif; ?>
0
votes

Your best bet is to extend the Walker class to walk through categories... The easiest way of doing this is to create your own Widget.

Here's one that I've created a while ago: https://www.dropbox.com/s/mazpb4cxmqracwo/adv_categories.zip

I'm not going to pretend that it's 100% functional but it allowed me to have categories with sub-categories on my blog.