Adding Categories Support to a Module

How to integrate Exponent categories into a module.  Obviously, each module MAY display or act on categories in a different fashion, however most of these steps still apply.

1. Update the Model by adding 'categories' to the $attachable_item_types array.  Otherwise, the categories never get attached to the item.


2. Update the item's ‘edit’ template by adding the category list dropdown (assuming the item is referred to as $record):

{if $config.usecategories}
    {control type="dropdown" name=expCat label="Category"|gettext frommodel="expCat" module="`$modelname`" orderby="`rank`" display=title key=id includeblank="Not Categorized"|gettext value=$catid}

3. Ensure the module controller does NOT contain ‘categories’ in the $remove_configs array.  Otherwise you can’t turn categories on.
4. The controller MUST use or call the expController::update() method to process categories, otherwise, if you have a class 'update()' method which does not call parent::update(), you’ll need to add this code.

if (array_key_exists('expCat',$this->params)&&!empty($this->params['expCat'])) {
    $catid = $this->params['expCat'];
    $this->params['expCat'][] = $catid;

5. Module records can easily be categorized and sorted by expPaginator:

  • • Add a check to see if using categories and add a ‘categorize’ parameter to the ‘$page = new expPaginator()’ call:
  • 'categorize'=> empty($this->config['usecategories']) ? false : $this->config['usecategories'],
  • Some additional expPaginator parameters affecting categories are:
    • groups - an array of category id's to limit the selectin to...e.g., easily display only a single category of items
    • uncat - a string to use in place of the generic 'Uncategorized' label for items without an assigned category.  This typically comes from the module configuration setting
    • dontsortwithincat - which does NOT group by category, yet still assigns category details to the item...e.g., you want the items sorted by published date regardless of assigned category.

6. At this point, the $page object now holds two sets of records:

  • $page->records is the linear object list now sorted first by `rank`ed categories, then by the $order/$dir
    • Each record has five (5) additional category properties

1. $record->catid is the category id

2. $record->`rank` is the category `rank`

3. $record->cat is the category title or name

4. $record->color is the category color

5. $record->module is the module the category applies to or blank for all modules (generally not needed at this point)

  • $page->cats is the categorized object list
    • Each ‘cat’ is indexed by category_id and has three (3) properties:

1. $cat->count is the total count of items in that category

2. $cat->name is the category name

3. $cat->records is the object records list as above sorted by $order/$dir

  • If  the 'usecategories' conguration setting is turned off, this list then becomes sorted by $order/$dir and grouped by the first letter of the $order entry if it is a string, or if it's being sorted by 'date', it'll be grouped by month/year or year (if more than two years from beginning to end).
    • E.g., if the $page $order is by ‘title’, the $page->cats object becomes an alphabetical listing of all items grouped by the first letter of the ‘title’, like a rolodex entry.
    • E.g., if the $page $order is by ‘published’, the $page->cats object becomes an chronological listing of all items grouped by the month/year of the ‘published’ date.  If the list spans more than two years from beginning to end, it will be grouped by year alone.

Updating or creating a view/template becomes the most complex part as you must deal with both categorized and uncategorized results.  The easiest to implement is to have an if/else control structure with two distinct views depending on if $config.usecategories is true.

1. To convert an existing paginated table/list in a view, look for the {foreach from=$page->records item=record} loop

  • Above that foreach loop line place a variable initialization
  • {assign var="cat" value="bad"}
  • Immediately below that foreach loop line enter code to print out the category
  • {if $cat != $record->expCat[0]->id && $config.usecategories}
        <h2>{if $record->expCat[0]->title!= ""}{$record->expCat[0]->title}{else}{'Uncategorized'|gettext}{/if}</h2>
  • And then on the line immediately before the close of that foreach loop (/foreach), place a counter:
  • {assign var="cat" value=$record->expCat[0]->id}
  • And you’ll likely need to add a style for the ‘item’ class to indent it from the category names and place a border above and below the category name (h2).
  • {if $config.usecategories}
    {css unique="categories" corecss="categories"}

2. For new views, it might be easier to use the new $page->cats record instead.  However, things might get strange if you have this view selected and turn off categories, etc…, you may just see one list/tab/accordion fold, etc…

  • Inside the main body area you could use the following (fyi, I have begun using an include file for the basic ‘item’ block since it’s the same across views and it makes fixing/updating code much easier):
  • {foreach from=$page->cats key=catid item=cat}
        <h2 class="category" {$cat->name}</h2>
        <div class="cat">
             {foreach from=$cat->records item=file}
                {include 'filedownloaditem.tpl'}
  • In this example the contents of the item div are found in the filedownloaditem.tpl file
  • The ‘h2’ will pick up its borders and the ‘item’ will pick up its indent from categories.css
  • The ‘cat’ div block surrounds all the items in that category if special styling is needed


Loading Help