Press "Enter" to skip to content

How to Create a Categories and Sub-categories Menu, Part 1

How Can I Create a Categories and Sub-categories Menu in WordPress?

I’ve seen this question asked a lot on the WP Forums and WP Stack Exchange along with several different answers. It really comes down to what you need. So, we’ll go over how to create a categories and sub-categories menu in two different ways and the pros/cons of each in this part of the tutorial.

First, before we get into this, did you know that a WordPress categories menu can be created without code and will also be editable on the dashboard? WpTavern tells you how!

Still interested in trying the PHP way? Awesome, let’s move on.

The two easiest ways to make this menu happen is to use either wp_list_categories or get_the_category_list. After we review them both, you can decide which option best suits your needs.

In Part 2 of this tutorial ( coming soon ), we’ll be going over how to write a categories and sub-categories menu from scratch using get_categories(). For now though, let’s get started with Part 1!

As I already mentioned, the two easiest ways are using either get_the_category_list or wp_list_categories. Below are two lists of what both functions have in common and what their differences are when being used with their defaults:

What They Have in Common:

  1. Both work just by copying and pasting even without optional parameters.
  2. Both work inside or outside the loop. ( If you’re still unclear about loops, check out this awesome article I found over at TreeHouse, A Comprehensive Beginners Guide to the WordPress Loop. )
  3. Both display as an unordered list.
  4. Both display the first level of categories.
  5. Both show the children/sub-categories with some differences, see “How They Differ, #5” below.
  6. Both hide categories that aren’t assigned to any posts with a minor difference, see “How They Differ, #6” below.*

How They Differ:

  1. Wp_list_categories has more options for customization than get_the_category_list.
  2. Wp_list_categories adds a title of “Categories” above the menu.
  3. Wp_list_categories displays the list items of the menu without the wrapping ul tags, which then leaves room for you to add them yourself along with your own custom class or ID. ( see screenshots below ) The get_the_category method however, already has the wrapping ul tags with a class of “post-categories”.
    #3 in "How They Differ" - it starts with an li so I can wrap it with my own ul tags
    #3 in “How They Differ” – wp_list_categories starts with an li so I can wrap it with my own ul tags

    #3 in "How they differ" - get_the_category_list includes the wrapping ul tags with the class of "post_categories"
    #3 in “How They differ” – get_the_category_list includes the wrapping ul tags with the class of “post-categories”
  4. Get_the_category_list needs “echo” before it to display.
  5. Wp_list_categories displays all the children/sub-categories and so does get_the_category_list. However, with the latter, the children are not nested inside of their parents. Each category regardless of whether they’re parent/child is it’s own link so visually, it may appear that the categories are on the same level when they aren’t. Wp_list_categories makes this distinction clearer. ( see screenshots below ) It also appears that get_the_category_list only goes two levels deep ( a parent and it’s sub-category ).
    get_the_category_list - Tutorials is actually a child category of WordPress but they appear as "siblings" in the code structure
    get_the_category_list – Tutorial is actually a child category of WordPress but they appear as “siblings” in the code structure

    wp_list_categories creates a ul with the class of "children" inside of it's parent, so unlike get_the_category_list, the child is inside the parent
    wp_list_categories creates a ul with the class of “children” inside of it’s parent, so unlike get_the_category_list, the child is inside the parent
  6. Wp_list_categories will display a category even if it’s not assigned to a post so long as one of it’s children/sub-categories is assigned to a post. Get_the_category_list will hide any unassigned categories.

There are some more differences in what parameters each of these offer and why they would matter to you. Let’s go over those next.

The Optional Parameters

Get_The_Category_List

This currently offers three optional parameters:

  1. Separator: Choose how you’d like each category separated (comma, bullet, space, whatever you’d like). If you’ve chosen a separator, the unordered list is removed and links are displayed instead with your custom separator in between. Since the ul tags are removed, so is the “post-categories” class that was wrapped around it by default.
  2. Parents: This can be used to “nest” the children in with their parent categories, but this method appears sloppy HTML-wise. “Single” will shove the child category next to it’s parent even though they share the same link. This method appears to behave inconsistently as well. Not sure what use this method would have – if anyone knows of one, I’d like to know. “Multiple” will create separate links for the children, but no nesting is happening. ( see screenshots below )
    Setting the $parents parameter to "multiple" will create a separate link for the child, which is better than "single" but still not nested within it's parent
    Setting the $parents parameter to “multiple” will create a separate link for the child, which is better than “single” but still not nested within it’s parent

    The $parents parameter set to "single" puts the "Tutorial" name in with "WordPress" but they're the parent link - which is weird...
    The $parents parameter set to “single” puts the “Tutorial” name in with “WordPress” – which is weird…
  3. Post ID: Inserting a post id in the third parameter will only pull the categories assigned to that specific post.

How to Use These Parameters:

The Codex shows you the placement of each parameter if you’d like to change one or all of them.

<?php get_the_category_list( $separator, $parents, $post_id ); ?>

Example 1, change separator parameter only with a comma and a space afterwards:

<?php get_the_category_list( ', ', '', '' ); ?>

Example 2, change the separator just like example 1, except we want to insert a post ID as well:

<?php get_the_category_list( ', ', '', '180' ); ?>

See the pattern? Whatever parameters you want to leave as default, just leaving the single quotes in place with nothing in between them will tell WordPress that you want to fall back to it’s default parameter. Now let’s move onto what wp_list_categories has to offer.

WP_List_Categories

This currently offers twenty-four optional parameters. I’ll try to keep this brief, and if the Codex explanation is self explanatory, I will just drop in the Codex’s definition. I’ve also marked the parameters I never use or haven’t experienced a project where I needed to use them with an asterisk (*) in case you want to skip those:

  1. Show Option All: This gives you a link to wherever your main blog roll is set up, whether it’s the default WP’s homepage or set to another page on your dashboard under Settings/Reading/Front Page Displays. And so you can specify what that links says above the menu here like “Back to blog” or “View all posts”. ( see screenshot )

    Setting show_option_all to "Back to Blogroll" inserted the link on top like this
    Setting show_option_all to “Back to Blogroll” inserted the link on top like this
  2. Order By: Order links alphabetically, by unique Category ID, or by the count of posts in that Category. There is also Term Group which is shown as an option but isn’t really explained. With a bit of research, from what I gather, no one really uses this? If there is a use for this, please leave me a comment, I’d love to know what it’s for. 🙂
  3. Style: Setting this to “none” will remove the unordered list and instead, have all the categories as links with line break tags separating them. ( see screenshot )

    Setting the style to "none" removes to ul and puts them as links instead
    Setting the style to “none” removes the ul and puts them as links instead with <br> tags
  4. *Show Count: Setting this to 1 or true ( no quotes ) will display the number of posts assigned to each category in between parenthesis after the category name.
  5. Hide Empty: Setting this to 0 or false ( no quotes ) will show all categories even if there are no posts assigned to those categories.
  6. *Use Des For Title: Setting this to 0 or false ( no quotes ) will remove the title attribute on category links that, by default, would use the category description. Of course this is assuming that your category description is filled in.
  7. Child Of: Putting a category ID here will cause it to display only the children of that category that you’re grabbing the ID from. So if you have a parent category named “Cakes”, and it’s sub-categories, “Chocolate”, “Vanilla”, and “Red Velvet”, and the ID of “Cakes” is 10, putting 10 for this parameter will have the menu display “Chocolate”, “Vanilla”, and “Red Velvet” only.
  8. *Feed: This is the text to include a RSS feed link for each category. So if you write “RSS” for this parameter, “RSS” will appear next to each category. When “RSS” is clicked, it will reveal the xml for an RSS Feed. More about RSS here.
  9. *Feed Type: This works with the Feed parameter. When you have an RSS feed link displayed, if you write something like “blog” in this feed type parameter, it will append /blog at the end of the RSS feed links. ( see screenshot )

    From setting feed to "RSS" and feed_type to "blog", you get the (RSS) link at the end of each category and the "blog" at the end of the urls
    From setting feed to “RSS” and feed_type to “blog”, you get the (RSS) link at the end of each category and the “blog” at the end of the urls
  10. *Feed Image: This parameter replaces the Feed parameter. Inserting a file path to an image here will use an image for the RSS feed links instead of the text you would insert in the Feed parameter.
  11. Exclude: Putting a category ID or multiple category IDs separated by commas in this parameter will exclude them specifically from the menu. It won’t automatically hide children of a category ID placed in this parameter.
  12. *Exclude Tree: Putting a category ID or multiple category IDs separated by commas in this parameter will exclude them from the menu along with their children/sub-categories.
  13. Include: Putting a category ID or multiple category IDs separated by commas in this parameter will only display categories from those IDs.
  14. *Hierarchical: Setting this to 0 or false (no quotes) will only show the first level of categories and no children/sub-categories.
  15. Title Li: If you want to get rid of that pesky “Categories” title that appears over the menu by default, leaving this empty will get rid of it. ( see screenshot )

    Get rid of the "Categories" title by having the title_li parameter as an empty string (see examples further below in article)
    Get rid of the “Categories” title
  16. *Show Option None: When there are no categories in the menu, this parameter allows you to customize what message will show. E.g. “There are no categories to display.”
  17. Number: An number placed in this parameter will be the number of categories to display in the menu. It decides which categories to show based on how many posts are assigned to the categories by default. So if I wrote 2 in this parameter, it will give me the two categories that have the most posts assigned to them.
  18. *Echo: Setting this to 0 or false ( no quotes ) will keep the menu from displaying and instead, return it as a string to be used with a variable. Honestly I’ve never used this and can’t think of a single example to show how this works. After finding a better explanation than what’s offered on the Codex from alchymyth, I understand more what this parameter is for, but not how it can be applied to real life use. Suggestions anyone?
  19. *Depth: This changes how many levels deep the menu goes. Meaning whether you want parents and just their direct children ( 2 levels) or perhaps you want the grandchildren ( Parents > Children > Grandchildren > GreatGrandChildren etc. ) which would be 3 levels deep instead. This is where you’d specify that number. Keep in mind that the Hierarchical parameter overrides this Depth parameter if it’s set to false.
  20. Current Category: By dropping in a specific category ID, this forces the “current-cat” class to be on that category whether or not it really is the current category. So if you’re on the category archive for “Cakes”, then the “Cakes” category will have the “current-cat” class by default. If you put a category ID that’s not “Cakes” in this parameter, then that class will be removed from “Cakes” and placed on the category of your choice.
  21. *Pad Counts: This parameter is set to true automatically if show_counts and hierarchical are true. This is what counts the posts assigned to the categories that display with show_counts.
  22. *Taxonomy: This is handy if you’re using custom taxonomies instead of WordPress’ native post categories. This is where you’d specify that you want to use your custom taxonomy in the menu instead.
  23. *Walker: This is a more advanced parameter, where the Walker_Category or Walker Class can be extended to further manipulate the default functionality of wp_list_categories.

As far as real life examples of how the Walker parameter is used, I have limited experience with this, and have a feeling that trying to explain the possibilities would get too deep and far off from the topic. Since we’re trying to keep this tutorial as an introduction to wp_list_categories, I’m going to leave the explanation to this parameter as is. I’m also going to direct you to this article on TutsPlus, Understanding the Walker Class.

*Tip on Exclude/Include: You would normally only use one of these. My rule of thumb is if the amount of categories I want to hide exceeds the total amount of categories existing, use include.

If the amount of categories I want to hide is less than the total amount of categories existing, then I use exclude instead.

This way I don’t have 20 categories total, exclude 15, and then only to display 5 of them. Instead, I just include those 5 IDs I want to display, and the other 15 are already hidden. Makes for cleaner code. 🙂

How to Use These Parameters:

To use these parameters, you have to create an array, and only list the parameters you want to change. You can place the array directly between the parenthesis of wp_list_categories, but I find it more readable and organized to place it outside the function and use a variable to connect the two.

Example, hide the “Categories” title above the menu with Title Li and order categories by Category ID with Order By:

<?php 
$my_cat_menu = array(
     'title_li' => '',
     'order_by' => 'category_id'
);

echo '<ul class="my-categories-menu">';
wp_list_categories( $my_cat_menu ); 
echo '</ul>';
?>

There are more awesome examples on the Codex.

And There You Have It!

As you can see, both get_the_category_list and wp_list_categories are easy choices when displaying a categories menu right out of the box. They each offer some options as far as customization goes, although wp_list_categories offers more than get_the_category_list.  Depending on what exactly you need, going over what each function offers can help you determine which one is right for you.

Now what if you want even more flexibility and customization? Perhaps you want more control over the structure of your menu. Maybe you just want parent categories to display and then children only show when you’re in their parent. If this sounds like you, in part 2 of this tutorial ( coming soon), we’ll be going over how to write a categories and sub-categories menu from scratch using get_categories(). Stay tuned!

2 Comments

  1. Trisha Dingillo
    Trisha Dingillo November 26, 2016

    this is great. at least i understand WHY I can’t do what I want. I have my site set up with many categories per post,to be used as cross database. I want to list categories in hierarchical order, but only for the posts. wp_list_categories looks beautiful, but it shows all categories. get_the_category_list does what i want but like you said, throws everything around. I’ve been looking into plain ol’ get_categories but still havent found it. Thanks for pointing me in the right direction!

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.