1

My goal is simple: to display a list of taxonomy terms (alphabetically), with the terms on the current node being highlighted by a current css class. I've tried using views of taxonomy term, but I can only get either the full list or the terms on the node to display, and I want something of a mashup.

So for the visual thinkers I want an output of this:

< ul >
    < li class="current" >Blue< /li >
    < li >Red< /li >
    < li class="current" >Rouge< /li >
    < li >Yellow< /li >
< /ul >

I feel like I'm about to have a very "duh!" moment, so please, enlighten me. Seems like this should be simple to do in Views, yet I can't seem to get it and will resort to doing it in the template.php file if I can't find an answer. Thanks for any help.

3
  • Where do you want this functionality to be applied to? In the full node display? In a View that displays nodes and you want this listing available per node result/row? Perhaps, you are using a Panel to display the node? Aug 4, 2015 at 16:11
  • I'd like it to display in a block on the node itself. I'm not using Panels, I'm looking for a block to display the full list on the right side of the page. The taxonomy itself is not very large max 25 items. I just want users to get a sense for what terms the content is related to by keywords.
    – Alison
    Aug 4, 2015 at 16:12
  • What I have is a list: alumnae-research, alumnae-research (with class current applied), careers (with class current applied), faculty-research (with class current applied), awards, careers, and courses. I'm using views_field_view to pull in a view that contains the list on the node to the view that has the whole list. What I need is to eliminate duplicate terms, and to put the whole list in alpha order. I've got query settings set to distinct, and pure distinct, and I've played with aggregate, but neither are doing what I want. Any other ideas? Thanks for the help!
    – Alison
    Aug 4, 2015 at 21:13

1 Answer 1

1

I think I have found a solution that achieves the desired result in good way (in terms of not writing spaghetti php or hardcoding stuff in the theming layer). Instead of providing the full configuration at once, I will try to guide you step by step.

1/ Create a new view (mine is called 'test') that only has a Block display, and displays Taxonomy terms for a specific vocabulary (mine is called 'Target Group'). Use 'HTML list' as the selected Format, make sure the 'Taxonomy term: Name' is added in the list of the displayed fields, also use 'Taxonomy term: Name' as a sorting option in ascending order, select 'Display all items' in the pager settings, and make sure query Distinct settings are DISABLED (we will achieve that via aggregation later on). Save your view. You can see the view results in the preview section of the view manage page, or place the block in the respective node display if you prefer to view it directly in the front end. At this point, you will be able to see a list of all the terms form the specific vocabulary.

2/ Add a new relationship to your view (in the Advanced section). The relationship should be the one labeled 'Taxonomy term: Content with term'. It is highly important (for the rest of the code that will be provided) that you choose this generic relationship option, instead of the more specific one labeled 'Taxonomy term: Content using Target group' (where Target Group is the vocabulary name I used for this example). Provide an identifier for this relationship - I left the default one labeled 'node'. Make sure that 'Require this relationship' is NOT checked - this will create a LEFT JOIN between the terms table and the node term data table. Now go to the fields section and add the field 'Content: Nid' and set it to use the relationship with the aforementioned identifier. Any other field settings do not matter for now - we will adjust them later on. Save your view. At this point you will be able to see plenty of duplicates for all terms, each one with a different nid. Good.

3/ Now go to the contexual filter section and add a new one for 'Content: Nid'. Make sure the 'node' relationship is used. For 'When the filter value is NOT available' choose 'Provide default value' and set 'Type' to 'Content ID from URL'. It is recommended to 'Specify validation criteria' as you see fit. Save your view. The configuration until this step, is actually the one presented in this excellent answer here which has some screenshots too. Up to this point, you will be able to see only the terms with which the current node is tagged. "Duhh, that was the original problem" you'll say, but bear with me as we take it one step further.

You see, when adding a contexual filter, views adds the restriction to the WHERE clause of the generated query (which is good and desired in the majority of cases). The current query generated is the following:

SELECT DISTINCT taxonomy_term_data.name AS taxonomy_term_data_name, taxonomy_term_data.vid AS taxonomy_term_data_vid, taxonomy_term_data.tid AS tid, taxonomy_vocabulary.machine_name AS taxonomy_vocabulary_machine_name, node_taxonomy_index.nid AS node_taxonomy_index_nid
    FROM 
    taxonomy_term_data taxonomy_term_data
    LEFT JOIN taxonomy_index taxonomy_index ON taxonomy_term_data.tid = taxonomy_index.tid
    LEFT JOIN node node_taxonomy_index ON taxonomy_index.nid = node_taxonomy_index.nid
    LEFT JOIN taxonomy_vocabulary taxonomy_vocabulary ON taxonomy_term_data.vid = taxonomy_vocabulary.vid
    WHERE (( (node_taxonomy_index.nid = '4072' ) )AND(( (taxonomy_vocabulary.machine_name IN  ('topics')) )))
    ORDER BY taxonomy_term_data_name ASC

But what we DO want in our case, is that the nid restriction is applied as an additional restriction to the LEFT JOIN with the node_taxonomy_index in order to filter the join and not the whole result set. Unfortunately, views does not support that out of the box but after some digging I found that it is programmatically supported in views_join handler which can be gracefully managed via hook_views_query_alter. So, moving on.

4/ In order to implement a hook, you will require a custom module. If you are not sure how, then read the respective documentation. Here is the implementation that removes the nid restriction from the where clause and adds it to the LEFT JOIN clause

function my_custom_module_views_query_alter(&$view, &$query) {
  if ($view->name == "test") {
    // try to resolve the nid from the contexual filter condition
    $contexual_nid = null;
    if (!empty($query->where)) {
      foreach ($query->where as $delta => $where_clause) {
        if (isset($where_clause['conditions']) && count($where_clause['conditions'])) {
          $condition = $where_clause['conditions'][0]; // in the current use case, there will be only one condition
          if (isset($condition['field']) && strpos($condition['field'], "nid") !== FALSE) {
            $contexual_nid = array_shift($condition['value']);
            // remove the nid constraint from the where clause
            unset($query->where[$delta]);
          }
        }
      }
    }
    // add the nid constraint to the relationship
    if ($contexual_nid != null && isset($query->table_queue['node_taxonomy_index']) && isset($query->table_queue['node_taxonomy_index']['join'])) {
      $join = $query->table_queue['node_taxonomy_index']['join'];
      $join->extra = array(
        array(
          "field" => "nid",
          "value" => $contexual_nid
        )
      );
      $query->table_queue['node_taxonomy_index']['join'] = $join;
    }
  }
}

So, at this point, you have a list that has tons of duplicates. "Duh, I had achieved that via 'views_field_view' and with less duplicates" you'll think. Well, no. First of all, the list is now sorted alphabetically, and second, getting rid of the duplicates, now that we are dealing with a single result set, is a piece of cake via aggregation. Back to the view administration then.

5/ In the Advanced section, set 'Use aggregation' to Yes. For field 'Content: Nid', click on the 'Aggregation settings' and set 'Aggregation type' to 'Count'. For field 'Taxonomy term: Name' the aggregation type should be the default 'Group results together'. Save your view and say goodbye to the duplicates.

6/ Last step in order to convert the 'Content: Nid' to useful markup. Click on the field which is now labeled '(node) COUNT(Content: Nid) (Nid)' and apply the following settings:

  • Create a label: unckeck
  • Exclude from display: check
  • REWRITE RESULTS: Rewrite the output of this field: checked
  • REWRITE RESULTS: Text: 'current' (the actual literal 'current' without the quotes)
  • NO RESULTS BEHAVIOR: Count the number 0 as empty: checked
  • NO RESULTS BEHAVIOR: Hide if empty: checked
  • NO RESULTS BEHAVIOR: Hide rewriting if empty : checked

And finally click on the Settings link for the HMTL list format and for 'Row class' enter token '[nid]'. Save your view. Everything should look as expected.

1
  • Thank you! I'm giving this a try right now. I do really appreciate your help.
    – Alison
    Aug 5, 2015 at 15:31

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.