Wednesday, April 20, 2011

Dealing with duplicate taxonomy terms

I haven't encountered this views bug until last Monday. I was working a view where I needed to show unique taxonomy terms in a grid. I was setting up something along the lines of "browse by category" view and what I got was a grid filled with multiple/duplicate terms.

Knowing the error, I started googling for answers but that exercise just made me run around in circles. Until I got to himerus' blog (he's also the guy working on the omega theme, you should check it out) and a node.

With the solutions I started trying them out. I settled for the "custom" module solution. The first time I tried it, it didn't work right off the bat. Take a look at the code:

// $Id$

* Implementation of hook_views_pre_render
* This function is in place to filter out duplicate taxonomy terms
* From listings. It will cycle each result, and store a new array of
* unique terms, and when a duplicate is found, will unset that result
* @param $view
function your_module_views_pre_render($view){
// first we make sure we are dealing with the correct view
if ($view->name == "your_view_name") {
  // create our array for comparisons
  $unique_tids = array();
  // let's cycle through each default result, and do some dirty stuff
  foreach($view->result AS $k => $result){
   if(in_array($result->node_node_data_YOUR_FIELD__term_data_tid, $unique_tids) || !$result->node_node_data_YOUR_FIELD__term_data_tid) {
    /* we already have seen this TID in the results, so blow that crap away
     * also will blow away any that are empty for some odd reason
   else {
    // this is a term we haven't seen, so let's not blow it away, but add
    // it to our array of unique id's to present as the "true" result of this view
    $unique_tids[$k] = $result->node_node_data_YOUR_FIELD__term_data_tid;
  /* now, we have an accurate unique list of terms in $unique_tids
   * next, we cycle those to reorder the crap random ordering
   * since these tids were pulled from the nodes in the order they were
   * set to sort from the node type view
  $alpha_arr = array();
  // cycle each of our unique tids, referencing the original key of the view->result array ($k)
  foreach($unique_tids AS $k => $tid) {
   // we need to grab the term now, not the tid to sort alpha
   $alpha_arr[$k] = strtolower($view->result[$k]->node_node_data_YOUR_FIELD__term_data_name);
  // sort the array, maintaining the $k key so that we may again reference back to the original data
  // create new array of results to overwrite the current one
  $new_results = array();
  /* cycle one last time now that we have unique terms, sorted alphabetically
   *    the point of this is to now take our $k reference, and grab the original $view->result data
   *    that references this item
  foreach($alpha_arr AS $v => $term_name) {
   $new_results[] = $view->result[$v];
  // get rid of the original result set
  // replace it with our new, accurate result set
  $view->result = $new_results;

Take a look at the "your_view_name", node_node_data_YOUR_FIELD__term_data_name and node_node_data_YOUR_FIELD__term_data_tid items. It should be easy to figure out the "your_view_name" thing. Just replace it with name of your views.

The  node_node_data_YOUR_FIELD__term_data_name and node_node_data_YOUR_FIELD__term_data_tid items is slightly different and made me to install a devel module to figure it out. Take a look at the $result array, I relized that I needed NOT to use the node_node_data_YOUR_FIELD__term_data_name or the node_node_data_YOUR_FIELD__term_data_tid but instead used a much shorter array key. So instead of "node_node_data_term_id__term_data_tid" use "term_id".

What's left is to turn on the module and flush the cache.

You should be golden!