September 20, 2005

Understanding the Category Listing Code

mtbadge-small.gif This tutorial is co-authored by LMT guest author 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.


Has this tutorial been helpful? Please consider linking to Learning Movable Type at http://learningmovabletype.com/ . Thanks!

Posted by Chad Everett on September 20, 2005 to Categories
Comments(31) | Email to a friend | Printer-friendly version


Trackback

If you would like to send a trackback
please use the following URL: http://learningmovabletype.com/cgi-bin/mt32/mt-tb.cgi/444

Comments

Great explanations! I still have trouble wrapping my head around how all the category tags work, and this goes a long way towards a clear understanding!

I'm looking for code to put the category keywords into a pull-down menu list and as soon as you select an item, you're taken to that page. I remember seeing an how-to somewhere, but I can't remember the URL and I think I threw out the printout.

Lola, you can use this as a base to create your drop-down list. Instead of list items (<li>), you would use options (contained within a select statement).

You would then populate the value of each with the path to the archive, and then you'd want a Javascript routine to take that value and redirect the user once an option has been selected.

It's a bit beyond the scope of this tutorial, but if you can handle the Javascript and form-building, this should get you there.

Thanks! By the way, I did find a tutorial in this site for the pull-down menu that I'd been asking for. The article is from November 2004, I believe.

In MT3.2, how do I control the order of top level categories displayed on the main blog page sidebar?
Alphbetical only is such a drag. There must be a plugin.

Thanks!
Don

Actually, that is the only option. There has been talk of such a plugin, but I don't believe that there has been any development of such a beast.

One option would be to put a number in front of the category - for instance:

1. Zebra
2. Apple
3. Bubba

So that the alpha sort would do what you want. Of course, you may not want the number there, which would make it tougher - you could use PHP to chop off the leading number perhaps.

Actually, you can use the Regex plugin to remove the numbers - works like a charm:

http://www.bradchoate.com/weblog/2002/07/27/mtregex

Thanks Chad,
You do great work man.

Just to confirm, the "table of contents" on this page is hand-coded Elise? Or is there some neat category PHP trick we can steal from you?

don

Hi Don,
All hand-coded. I rarely change the categories so this is the best way I've found to get the flexibility I want for the listing.

Elise & Chad, GREAT article, it has really helped me to understand how everything (category-wise) is supposed to flow.

Elise, you hard code your categories correct? Do you put them into a module or php and do an include?

I am thinking of hard coding my categories as well because I want each parent to be a link which then drops opens the sub categories. (taken from one of your previous tutorials).

Thanks so much!

Thanks Chad,
You have done an amazing job =)

jyoseph, I can't speak for Elise, but I would use an index template and include via PHP before I used a module. This is for two reasons.

The first is that if you want to update the menu, and you are using a module, you will then have to rebuild all the templates using an MTInclude to pull in the contents of the module. Not impossible, but a bit of a pain. If you use PHP, as soon as the change is saved, it's live on your site.

The second is that the MTInclude process takes a lot of resources. If you're building a single page, it's not (generally) an issue. If you use dynamic publishing, you won't really see a problem for this reason - the page is rendered one-at-a-time (basically). But if you rebuild a few hundred individual archives, and each of those has a couple of MTIncludes on it, you'll see a noticeable lag.

Chad, many thanks. Not only did that help (in this situation) but it helped me to curb using the MTInclude so much. I swear I overuse that feature big time.

Thanks again!

Question, if someone can answer: would there be a way to, say, have a thumbnail image and title as the "title" for a post/article, so that I could have images of products reviewed alongwith the titles of the reviews display when you click the "reviews" category link? If so then this is what I'm looking for. Preferably I'd have an option of having, say, normal text display for blog entries, pictures of products in the case of reviews, and so on. Is there a plugin for this?

Hi Peter -

You don't really need a plugin for this. You can just use the power of MT to make it happen. All you need is a handful of images (however many you would like to display).

Simply use <MTCategoryLabel dirify="1"> within the declaration of your image. That way each page gets its picture named dynamically (not truly dynamic, but you get the idea).

For instance, you might see something like this:

<img src="/images/<MTCategoryLabel dirify="1">.jpg" />

If your category is "Reviews", your image name would become "/images/reviews.jpg". You could use other tags (perhaps the entry title?) to create other names. Then all you need is to have images that correspond to the name.

Question:

I'm using MT in a corporate setting to post documents and instructions for clients--so I'd like to protect these from being viewed by general public.

My hosting service has a feature to password protect a given category, but the problem is I don't know how to post to a category without the posting being displayed on the main/index. Am I stretching MT in a direction it isn't designed for here? OR is there a real work-around here??
The one plugin I found does not seem too recent or solid...

I need to do something with my category archives pages but I can't figure it out. I have 3 different piece of codes which I want to use in deferent levels of categories. I mean:
If I want to use code1 for category level1 and code2 for category leve2 and code3 for category leve3, what can I do?
( level2 is subvategory of level1 and level3 is subcategory of level2).

Hi Jordan -

One option would be to use Arvind's MT-Protect plugin.

Another would be to use the power of MT's built-in template tags to do the job. The MTEntries container will allow you to specify the category of those entries. Just add category="This" to the container. Using this method, you can select all categories you want to appear on the main index (and leave out those you don't), but it might get a bit long if you have a bunch of categories.

There are also alternatives if you'd like to work with dynamic publishing (Smarty) or even custom plugins, but I'm not aware of any that are currently available to the public at large. Contact me if you're interested in that sort of solution.

As to different levels of code for different levels of your categories: That is possible, but it gets a bit tricky, and you may have trouble doing it at multiple levels.

Essentially you have to use the conditional tags, such as MTHasNoParentCategory (for top-level) or the MTIfIsAncestor and MTIfIsDescendant tags. You could also assign the CSS style (class and/or id) based on the category name, then style that category in your CSS.

Yes. I could do that. thanks a lot. But it is usable only for 3 levels.Any way. Now One problem is left: how to do this with monthly, weekly and daily archives.I need to define a path to a php file in each of these pages, but It works only for monthly pages.Is there any tag inside date-based archives to determine which archives is being processed?What am I supposed to do?

Well, I'm not really sure what you are after. There are lots of things you can do with archives, and especially in conjunction with PHP. But it's not really appropriate to this tutorial - so it would probably be better focused on another tutorial (there are many!) or on the support forums (link just below).

I'm interested in splitting my categories into more pages.

Let's say I have 150 posts in 1 category. How can I make it display only 10 posts per page within that category?

Thanks in advance :)

You have a few options for paginating your archives. If you use dynamic publishing, you can use the power of Smarty to do this right within your templates.

Though slightly dated, you may also be able to use MTPaginate for your needs if you use static publishing (it still requires PHP).

And if you don't understand any of this, there are a number of options available for Movable Type Consulting - of which I am just one.

Taran, maybe u can answer this

People linnking to my blog from technorati recieve a link that looks like this...


http://www.mopocket.com/cell_phones/#000030

which is a greta article about Cell Phonnes for dogs.

which brings them to the category page but not to the article... how do I fix this?

and why is technorati only picking up my story by categories and not individual archive?


I use MT

Justin

Hi Justin -

Not sure who Taran is, but that's not too important.

The problem appears to be one of the preferred archive type that you have chosen.

Go into the settings for this blog (config if prior to 3.2) and look for "preferred archive type". Looks like yours is set to "category". Change it to "individual", save and rebuild the entire site.

This will change your preferred entry link from the category page to the individual page (which I notice you have already, so it should do the trick).

Hope ths helps!

Hi there, I'd like to make the subcategories collapsile, like I found it on this page http://performancematters.europe.yahoo.com/. You can easily copy the JS of the source code, but I don't know, how to arrange the categories tags, that the subcategories collapses. There are two <ul> tags needed, one for the complete categories section and one only for the subcategories. Any hints?

Cheers,
Konny

Is there a way to create "hot categories"? a list of 5 categories that have the most posts in them? I tried asking in MT Forums but nobody seems to know.

There is nothing within MT to do this, but I have created a plugin that can handle the task. If you are interested, please contact me directly (you may leave a comment here and I will see it, or use one of the contact methods on my web site).

Hi!

It's possible to show only one category and link it to his archive, ignoring the other categories? How can I do that?

Hi Jose -

It depends a bit on what you need. You can include a single category and the link to the category by just creating the HTML. For the work that's involved to do it, that's probably the best route.

Alternatively, you could try the MTCategories loop along with something like the FilterCategories plugin. But you'd have to build a loop, then specify the category along with the tags you need - so it's really a lot of extra work (for you and for the rebuild) to do it this way.


Post a comment

(Before posting a comment please see the Comments and Trackbacks Policy. Do you need help troubleshooting your weblog? Please post questions and requests for support at the MT Support Forums. Thanks!)




Remember Me?

(you may use HTML tags for style)

Email to a friend

Email this article to:


Your email address:


Message (optional):