Skip to content
philcali edited this page May 9, 2012 · 4 revisions

Welcome to the Category Sorter wiki!

Adding Custom Sorting

Category Sorter was made with the custom sorting in mind. The plugin ships with two sorting routines:

  1. Do nothing: doesn't perform any sort
  2. Alphabetical: Sorts category names (sub-categories individually), alphabetically

Any plugin can add a new sorting method, but local plugins are ideal.

Category Sorter populates its sorting methods by allowing plugins to handle the category_sort_gather event. This event takes in an stdClass object with the array field sorts.

It handles its own event to add the default sorts, something like this:

<?php
abstract class local_category_sort {

    public static function sort_gather($sorter) {
        $sorter->sorts['do_nothing'] = array('title' => get_string('do_nothing'));
        $sorter->sorts['local_category_sort'] = array(
            'title' => get_string('sort_type', 'local_category_sort'),
            'includes' => '/local/category_sort/lib.php',
            'function' => array('local_category_sort', 'sort_categories')
        );
        return true;
    }

    function sort_categories($categories, $parent = 0) {
        return function($a, $b) { return strcmp($a->name, $b->name); };
    }
}

This snippet will give you an idea about what's going on here.

  1. The method sort_gather is the method handling the category_sort_gather event.
  2. sort_gather populates the two routines. A routine is an associative array with the key title being set to its descriptive name.
  3. The sort_categories generator method is referenced.
  4. The generator produces a callback to be used in uasort, for the newly assigned sortorder.

Putting it all together

I'll now make a fictitious category local sorter that sorts the categories by course count (highest to lowest).

local/category_count_sort/db/events.php

<?php

$handlers = array(
   'category_sort_gather' => array(
      'handlerfile' => '/local/category_count_sort/lib.php',
      'handlerfunction' => 'category_count_sort_gather',
      'schedule' => 'instant'
   )
);

local/category_count_sort/lib.php

<?php

function category_count_sort_gather($sorter) {
   $sorter->sorts['category_count_sort'] => array(
      'title' => 'Course Count (Highest to Lowest)',
      'includes' => '/local/category_count_sort/lib.php',
      'function' => 'category_count_sort_generator'
   );
   // This is important to pop the event queue
   return true;
}

function category_count_sort_generator($categories, $parent = 0) {
   return function($a, $b) {
      return $a->coursecount < $b->coursecount ? 1 : 0;
   };
}

Run Notifications to finish the installation, and you should be able to use the new method.

The Possibilities

It's possible to produce a number of generators in a single plugin. The question remains: Why does the generator take in $categories and a $parent? My answer is: Why not?

With the presence of $categories and parent, it's possible to sort specific categories (sub-categories) without any core changes. For example, let's say I want to keep Miscellaneous at the top of the list, ignore the sort if there's less than 5 categories except if the $parent is MATH, sort the others by their names, and bury courses with 0 courses. That generator would look something like this:

<?php

function combined_generator($categories, $parent = 0) {
   return function($a, $b) use ($categories, $parent) {
      // Leave alone
      if (count($categories) < 5 and $parent->name != 'MATH') return 0;

      // Always on top
      if ($a->name == 'Miscellaneous') return -1;

      // Bury empty categories
      if (empty($a->coursecount)) return 1;

      // Traditional alphabetical the rest
      return strcmp($a->name, $b->name);
   };
}