Colorfield logo

Drupalicious

Published on

Alter Views sort by taxonomy weight

Authors
Scale
Photo by Piret Ilver on Unsplash

The use case is to sort a list of users by job title, where job title is a term reference to a dedicated vocabulary.
The sort is done by the job title term weight (defined via the vocabulary list).

I choosed to apply a custom sort function on a view, instead of a custom dynamic / entity query for two reasons :

  1. the client have access to Views so he can continue to apply changes via the UI (format, fields, filters, ...)
  2. the query involves third party database (CiviCRM) that is already well handled by the CiviCRM Entity module so we can avoid custom API call to CiviCRM.
/**
 * Implements hook_views_pre_render().
 *
 * Applies custom sort by job title weight on a view.
 *
 * @param $view
 */
function my_module_views_pre_render(&$view) {
  if($view->name == 'my_view') {
    // load vocabulary
    $job_title_vocab = taxonomy_vocabulary_machine_name_load('job_title');
    $job_titles = taxonomy_get_tree($job_title_vocab->vid);
    // index for fast weight retrieval, avoids nested foreach
    $job_title_weight = array();
    foreach ($job_titles as $job_title) {
      $job_title_weight[$job_title->tid] = $job_title->weight;
    }
    foreach ($view->result as $user) {
      // assume we fetch the first one if multiple
      $user_job_title = $user->field_field_job_title[0]['raw']['tid'];
      // append my_module_job_title_weight property to sort on, shorthand
      $user->my_module_job_title_weight = $job_title_weight[$user_job_title];
    }
    usort($view->result, '_my_module_job_title_weight_compare');
  }
}

/**
 * Comparable functor to be used by usort.
 *
 * @param $a
 * @param $b
 *
 * @return int
 */
function _my_module_job_title_weight_compare($a, $b) {
  if ($a->my_module_job_title_weight == $b->my_module_job_title_weight) {
    return 0;
  }
  return ($a->my_module_job_title_weight < $b->my_module_job_title_weight) ? -1 : 1;
}