Learning Movable Type: Understanding the Category Listing Code


mtbadge-small.gif This tutorial is co-authored by LMT contributor Chad Everett of Everitz Consulting and Elise Bauer of elise.com.

Movable Type allows you to create categories and sub-categories for organizing your entries. The default MT3.2 Main Index template includes code to list these categories in the sidebar section. This tutorial will attempt to explain the tags used in this code and how they work together.

Categories, Sub-categories, Parent, Child, and Levels

The only difference between a category and a sub-category is that the latter will always have a "parent" category. The sub-category is still a category, and everything else remains the same as any other category. But by having sub-categories, you can provide better organization for your site. One example might be to put sub-categories of "Movable Type" and "Typepad" under a parent category of "Tips", to better classify the information you are creating.

Any category with such a "parent" will be considered a "child". Additionally, any category (even a sub-category!) can have its own children as well. Because of this, within this tutorial, you will see the term "level" used frequently. A parent category (Tips) is on one level. The child category (Movable Type, Typepad) is another. In turn, the child category may have children itself (Plugins, Styles, Templates), creating still another level.

The Default Category Listing Code

Here is the code from the Main Index template:

<MTTopLevelCategories>
<MTSubCatIsFirst><ul></MTSubCatIsFirst>
<MTIfNonZero tag="MTCategoryCount">
<li><a href="<$MTCategoryArchiveLink$>"
title="<$MTCategoryDescription$>"><MTCategoryLabel></a>
<MTElse>
<li><MTCategoryLabel>
</MTElse>
</MTIfNonZero>
<MTSubCatsRecurse>
</li>
<MTSubCatIsLast></ul></MTSubCatIsLast>
</MTTopLevelCategories>

<MTTopLevelCategories> <MTTopLevelCategories> is a container that processes the code within, starting with the current highest level category. When it gets to the <MTSubCatRecurse> tag, it then repeats the process with the next highest level of category, and so on, through all levels of sub-categories.

<MTSubCatIsFirst> <MTSubCatIsLast> These tags simply indicate if a particular category is the first in the list or the last in the list, respectively. As you can see these tags open the <ul> and then close the <ul> at the end of this section of code. So, the first category in the list of categories opens the unordered list tag - <ul> - which pulls from your stylesheet the direction of how to display an unordered list. (Unordered lists are usually displayed with bullet points. Ordered lists - <ol> - are usually displayed numbered 1, 2, 3, etc.) Likewise, the last category in the list of categories closes the unordered list tag.

<MTIfNonZero>, MTCategoryCount and <MTElse> The <MTIfNonZero> tag compares the value of the tag (in this case, MTCategoryCount) to zero. If there are entries within a category, the MTCategoryCount will be greater than zero and a link will be provided to the category page. If the there are no entries in the category, the MTCategoryCount will equal zero and <MTElse> will come into play and only the category label will be shown, without a link.

In either case, an <li> tag is opened which instructs the browser that what comes next is a list item. The <li> tag is closed after the processing of the <MTSubCatsRecurse> is complete.

<MTSubCatsRecurse> This tag says to process this hunk of code for each level of sub-categories under this one (and so on).

"Recurse", by the way, is a programming term, indicating to "use recursion". In other words, it is the ability of the routine - in this case the <MTTopLevelCategories> container - to call itself over and over again.

In this example it means that the container will continue to loop through each "level" of categories, until it reaches the end of that level. At this point, if on a "lower" level (that is, a sub-category), processing will return to the next higher level (the "parent"), where the loop will complete. If the loop is still on a lower level, it will end that loop, and return up to the next level. And so on.

If you remove this tag, the code will produce the same structure - but it will only be for the top-level categories (no sub-categories). If you include this tag, each time through the loop (that is, for each current category), it will redo the structure for the categories below that one. You can perhaps see this best by looking at the HTML.

For top-level categories only (no recurse tag, meaning no sub-categories at all), you might see something like:

<ul>
  <li>News</li>
</ul>

But with the recurse tag, you will be able to produce something like this:

<ul>
  <li>News
  <ul>
    <li>Local</li>
    <li>World</li>
  </ul>
  </li>
</ul>

To explain how this works...

First, the opening <ul>, then the first category (the only one in this sample). Prior to that tag being closed, the recurse tag runs - and realizes there are some sub-categories for the current category.

So it opens a new <ul> for this level of sub-categories, which in turn has its own items in the list. When that category is at the end, it closes that list with </ul>, then closes that item (News) with </li>. Finally, we're at the end of the entire category list, so the top-level list is closed with </ul>.

This illustrates a more likely example, with multiple categories at each level:

<ul>
  <li>News
  <ul>
    <li>Local</li>
    <li>World</li>
  </ul>
  </li>
  <li>Recipes
  <ul>
    <li>Beef</li>
    <li>Chicken</li>
    <li>Pork</li>
  </ul>
  </li>
  <li>Tips
  <ul>
    <li>Movable Type
    <ul>
      <li>Plugins</li>
      <li>Styles</li>
      <li>Templates</li>
    </ul>
    </li>
    <li>Typepad</li>
  </ul>
  </li>
</ul>

You'll notice that under "Tips", the recurse tag pulls up "Movable Type", similar to how "News" worked earlier. But when this category is the "current" category, it will again pull up the recurse tag, now at the next "level" down in the category listing. This next level down generates the list for those sub-categories: "Plugins", "Styles" and "Templates". The structure is all the same - pulled from the top-level. It just runs it over and over again as needed for all of the sub-categories.

Customizing the Category Listing

Not Showing Categories without Entries The default code will display the name of all of your categories, whether or not you have entries in them. If you want to display only those categories which currently have entries, you need to remove the <MTElse> condition from the equation. Your resulting code would be something like this:

<MTTopLevelCategories>
<MTSubCatIsFirst>    <ul>    </MTSubCatIsFirst>
<MTIfNonZero tag="MTCategoryCount">
<li><a href="<$MTCategoryArchiveLink$>" title="<$MTCategoryDescription$>"><MTCategoryLabel></a>
</MTIfNonZero>
<MTSubCatsRecurse>
</li>
<MTSubCatIsLast>    </ul>    </MTSubCatIsLast>
</MTTopLevelCategories>

Note that if you have a top level category that is empty, but contains sub-categories that have items, removing this piece of code will create an unusual display as those sub-categories will be placed in the same list as the prior category. This is because the <MTCategoryCount> tag doesn't include the count of sub-category items beneath the current category.

If you use sub-categories and you do not want to show sub-categories or top level categories unless they contain items, one method you can use is to install the SubCatCount plugin. With this plugin installed, your code would look like this:

<MTTopLevelCategories>
<MTSubCatIsFirst>    <ul>    </MTSubCatIsFirst>
<MTIfNonZero tag="MTSubCatCount">
<li>    <a href="<$MTCategoryArchiveLink$>" title="<$MTCategoryDescription$>"> <MTCategoryLabel> </a>
<MTElse>
<li>    <MTCategoryLabel>
</MTElse>
</MTIfNonZero>
<MTSubCatsRecurse>
</li>
<MTSubCatIsLast>    </ul>    </MTSubCatIsLast>
</MTTopLevelCategories>

Limiting the levels of sub-categories displayed

If you have several levels of sub-categories, you may want to limit the display of them in your Category List to only a few levels. To do this add a max_depth attribute to the recurse tag like so:

<MTSubCatsRecurse max_depth="3">

Not Showing sub-categories

To show only primary categories, and not sub-categories in your listing, remove the <MTSubCatsRecurse> tag from the code entirely. This is not the same as max_depth="1". That will include the top-level categories and the first level of sub-categories.

Adding an Entry Count

To add the the number of entries in parentheses after each category or sub-category label, you would use the <MTCategoryCount> template tag. Something like this displays the added code at the end of the link to the category archive page:

<li><a href="<$MTCategoryArchiveLink$>" title="<$MTCategoryDescription$>"><MTCategoryLabel></a> (<MTCategoryCount>)

If you wanted to instead display the sub-category count at that point, you should use <MTSubCatCount> instead of <MTCategoryCount>, as mentioned previously, by installing the SubCatCount plugin.

Displaying Categories in a Custom Order

This tip comes in from an LMT reader. To come up with your own custom order of categories or subcategories, without the use of a plugin, do the following:

a. Name the categories 1, 2, 3 ... in the order you want them to appear. b. Use the description field for the name of the category. c. Replace MTCategoryLabel with MTCategoryDescription in your category display code.

Many thanks to Hugo Paulissen for this last tip.


Posted by Chad Everett on September 20, 2005 10:13 AM to Learning Movable Type http://www.learningmovabletype.com/