SubCategories Plugin Documentation
Installation
Download one of the following files:
And install the files contained within as follows:
-
sub_cats.pl should be placed in the plugins/ directory
-
mt-sc.cgi should be placed in the main MT directory, and have its permissions set so it can be executed (usually chmod 755, but not always)
-
SubCats.pm and SubCategory.pm should be placed in the extlib/rayners/ directory (Note: the rayners/ directory under extlib/ will most likely need to be created, unless you have installed another plugin that requires it)
Setup
Click the link provided for SubCategories in the MovableType Main Menu to bring up the setup interface. If you are using a version of MovableType earlier than 3.0, you will need to manually load mt-sc.cgi in your browser.
If the link for the plugin does not appear, please verify that all files are installed in the correct locations according to the Installation section.
To set a parent/child relationship, first scroll to the blog in which you wish to set that relationship. Then, select the parent category from the first dropdown list and the child category from the second. Click the Set button and the child category will be set as a subcategory of the parent if there are no problems.
To remove a parent/child relationship, click the unset parent link next to any child category.
To configure the SubCategories options, enter the desired Category Label Delimeter and check the checkbox if you would like to try the Parent Category Archive Rebuilding feature.
Category Label Delimeter
This feature provides the ability to specifiy a category hierarchy within the label of a single category in the MovableType category creation interface.
For example, say you wanted to create the following category hierarchy, and none of these categories currently exist.
-
Alpha
-
Beta
-
Delta
-
Gamma
-
-
To start with, create a category through MT with the following label (assuming the default Category Label Delimeter of '::'):
Alpha :: Beta :: Delta
To verify the hierarchy creation, bring up the SubCategories configuration interface and verify that the following hierarchy has been created:
-
Alpha
-
Beta
-
Delta
-
-
There are now two category labels that you can use to add Gamma into the category hierarchy:
Alpha :: Beta :: Gamma
Beta :: Gamma
The latter is preferable as the Alpha -> Beta relationship has already been established.
Parent Category Archive Rebuilding
If enabled, when an entry is saved with a primary category defined (this does not affect secondary categories), each of the category archives for all of the ancestor categories 1 will be rebuilt.
This is an experimental feature currently, as the plugin must create a new instance of the main MovableType class within itself to do the rebuilding. This has been submitted to SixApart and will be addressed in a future release.
Template Usage
MTSubCategories
MTSubCategories is a MTCategories replacement that will handle the subcategories that you define.
Arguments:
-
include_current: set to 1 if you wish the current category to be included in the list (e.g. if this was used within a MTEntryCategories container)
-
sort_method: fully qualified Perl method name (e.g. package::SubPackage::method_name) to be used with sort to sort the categories. Please see the example for more details.
-
sort_order: set to 'descend' (reverse alphabetical order) if you would prefer the categories not appear in alphabetical order, only used if sort_method is not set
MTSubCatsIsFirst
A conditional tag that is evaluated if the current subcategory is the first of its level.
MTSubCatsIsLast
A conditional tag that is evaluated if the current subcategory is the last of its level.
MTSubCatsRecurse
Recursively call the MTSubCategories container with the subcategories of the current category.
Arguments
-
max_depth: the maximum depth of recursion (e.g. to only go down two levels, max_depth='2')
MTParentCategories
A container tag that starts with the top level parent of the current category and continues on down the path to the current category with each iteration of the container.
Arguments:
-
glue: the text to use to tie the list together
-
exclude_current: exclude the current category from the list
MTEntriesWithSubCategories
A replacement MTEntries container tag that is aware of subcategories. Replace MTEntries with this in your Category Archive Templates to make them include all of the entries for that category's subcategories.
Arguments:
-
category: if set, MTEntriesWithSubCategories will expand it to an ORed list of the category and all of its subcategories (e.g. "Parent Category OR Sub Category 1 OR Sub Category 2 OR Sub Sub Category 3 ... ")
-
any other arguments are passed directly to MTEntries
MTParentCategory
A container tag that applies only the immediate parent of the current category.
MTSubCategoryPath
A short-cut tag (just a regular tag), that returns as if the following template code were being used:
<MTParentCategories glue="/"><MTCategoryLabel dirify="1"></MTParentCategories>
MTHasSubCategories
A conditional tag that is evaluated if the current category has subcategories below it.
MTHasParentCategory
A conditional tag that is evaluated if the current category has a parent category above it.
MTHasNoSubCategories
A conditional tag that is evaluated if the current category has no subcategories below it.
MTHasNoParentCategory
A conditional tag that is evaluated if the current category has no parent category above it. This tag allows you to address the HTML relating to the top-level categories as they have no parents. If you are using nested unordered lists to create a CSS dropdown menu you'll need to apply a CSS id selector to just the root tag (if it were applied to all tags the code would be invalid). Here's how:
<ul<MTHasNoParentCategory> id="nav"</MTHasNoParentCategory>>
MTTopLevelCategories
A clone of MTSubCategories, but it always starts at the top level of the category hierarchy.
MTTopLevelParent
A container tag that applies only the top level parent category of the current category.
MTIfIsAncestor
A conditinal tag that is evaluated only if the current category is an ancestor of the given category (i.e. on a path from the top level categories to the given category, the current category appears).
Arguments:
-
child: the possible child category
MTIfIsDescendant
A conditional that that is evaluated only if the current category is a descendant of the given category (i.e. on a path from the top level categories to the current category, the given category appears).
Arguments:
-
parent: the possible parent category
Examples
Category List
Here is the template code to generate a list of categories using nested unordered lists:
<MTSubCategories> <MTSubCatIsFirst><ul></MTSubCatIsFirst> <li> <MTCategoryLabel> <MTSubCatsRecurse> </li> <MTSubCatIsLast></ul></MTSubCatIsLast> </MTSubCategories>
Category Archive File Name
Here is the template code to generate a file name for a category archive:
archives/<MTSubCategoryPath>/index.php
Category Breadcrumbs for an Entry
Here is the template code to generate category breadcrumbs for a given entry:
<MTEntryCategories glue=", "> <MTParentCategories glue = "→ "> <a href="<$MTCategoryArchiveLink$>" title="<$MTCategoryDescription$>"><$MTCategoryLabel$></a> </MTParentCategories> </MTEntryCategories>
Here is an example of a custom category sorting method (placed in a
extlib/rayners/CategorySorting.pm in this example): And the template code to make use of it: rayners::SubCategory is a subclass of MT::Category that
gives a plugin developer access to the data that is created by the
SubCategories plugin. To create a rayners::SubCategory object from a given
MT::Category object: If called in a scalar context, this method will return the parent category as
a rayners::SubCategory object, or undef if there is none. If called in an array context, this method will return the parent categories
as an array of rayners::SubCategory objects, with the top level parent
at the end of the array, or an empty array if there are none. This method will return an array of immediate children categories as an array
of rayners::SubCategory objects. Returns a true value if the category is on the path from the top level
categories to $child. Returns a false value otherwise. Returns a true value if $parent is an ancestor of the category.
Returns a false value otherwise. This code will create an array containing all of the SubCategories for a
given category, any number of levels down. Custom Category Sorting
Method
package rayners::CategorySorting;
my %category_priorities = (
# I want 'MT Plugins' to appear before 'MT Brainstorming'
# followed by the rest
'MT Plugins' => 1
'MT Brainstorming' => 2,
# And I want 'SubCategories' to be the first plugin listed,
# followed by 'Entry' and then the rest of the plugins
'SubCategories' => 1,
'Entry' => 2,
);
sub cat_sort ($$) {
my ($a, $b) = @_;
my $a_pri = $category_priorities{$a->label} || 1000;
my $b_pri = $category_priorities{$b->label} || 1000;
unless ($a_pri == 1000 && $b_pri == 1000) {
# At least one of them has a defined priority
# so sort on that
return $a_pri <=> $b_pri;
}
# Both are the default value (1000)
# so sort alphabetically
return $a->label cmp $b->label;
}
<MTSubCategories sort_method="rayners::CategorySorting::cat_sort">
...
</MTSubCategories>
API Usage
copy_cat ($cat)
my $subcat = rayners::SubCategory->copy_cat ($cat);
parent
# Immediate parent
my $parent = $cat->parent;
print "Parent is ".$parent->label;
# Array of parents (immediate ... top level)
my @parents = $cat->parent;
while (my $parent = pop @parents) {
print $parent->label." -> ";
}
print $cat->label."\n";
children
# Array of children
my @children = $cat->children;
if (scalar @children) {
print "Children of ".$cat->label." are: ";
print join (", ", map { $_->label } @children);
print "\n";
}
is_ancestor ($child)
my $parent_cat = rayners::SubCategory->load ({ label => 'MT Plugins' });
my $child_cat = rayners::SubCategory->load ({ label => 'SubCategories' });
if ($parent_cat->is_ancestor ($child_cat)) {
print $parent_cat->label." is an ancestor of ".$child_cat->label."\n";
}
is_descendant
($parent)
my $parent_cat = rayners::SubCategory->load ({ label => 'MT Plugins' });
my $child_cat = rayners::SubCategory->load ({ label => 'SubCategories' });
if ($child_cat->is_descendant ($parent_cat)) {
print $parent_cat->label." is an ancestor of ".$child_cat->label."\n";
}
Examples
Generating a Complete List
of SubCategories
sub complete_subcats {
my ($cat) = @_;
# The array to return containing all of the children
my @cats;
# The temporary holding array
# seeded with the given categories children
my @kids = $cat->children;
# While there are categories in the holding array
while (my $c = shift @kids) {
# Add their children to the holding array
push @kids, ($c->children);
# Then add them to the array to return
push @cats, $c;
}
return @cats;
}
