Syndicate

Feed

Putting some order in your terms

In Wordpress, unlike in Drupal, terms are not lumped together in posts. Each Wordpress vocabulary has its own “template tag”, and the ones that come out-of-the box are: the_tags(), and the_category(). The following theming tweak is about putting order in Drupal terms before they're output to screen. It you need to break up your terms by vocabulary before you display them, read on.

Here's a Wordpress blog entry:

Terms presented by vocabularies in Wordpress

I will present an all-purpose solution that will print all terms by vocabulary. Each vocabulary list will be wrapped in its own HTML element, and I will use the vocabulary name as label for each term list — hence a label you can edit in the Administration Section of your Drupal site.

Solution

  1. Edit template.php to rebuild your $node->taxonomy array...

  2. ... and re-theme that array into a new $terms variable... and then...

  3. style your terms as needed in style.css.

Say you have two vocabularies, one for “free tagging”, and another for filing posts under sections, like so:

My vocabularies listed

You may not like your free tags to be lumped together with your “Filed under” terms. You may prefer to see something like this:

Terms presented by vocabularies in Drupal

Let's get to it.

You will use a prepocess function for your node template — and add it if such function has not already been defined. Open your theme template.php file in a text editor, and add the following code (please read the comments):

/**
* Override or insert PHPTemplate variables into the node template.
*/
function phptemplate_preprocess_node(&$vars) {
  // If we have any terms...
  if ($vars['node']->taxonomy) {
    // Let's iterate through each term
    foreach ($vars['node']->taxonomy as $term) {
      // We will build a new array where there will be as many
      // nested arrays as there are vocabularies
      // The key for each nested array is the vocabulary ID     
      $vocabulary[$term->vid]['taxonomy_term_'. $term->tid]  = array(
        'title' => $term->name,
        'href' => taxonomy_term_path($term),
        'attributes' => array(
          'rel' => 'tag', 
          'title' => strip_tags($term->description)),
        );       
    }
    // We will get rid of the old $terms variable
    unset($vars['terms']);
    // And build a new $terms
    foreach ($vocabulary as $vid => $terms) {
      // Getting the name of the vocabulary
      $name = taxonomy_vocabulary_load($vid)->name;
      // Using the theme('links', ...) function to theme terms list
      $terms = theme('links', $terms, array('class' => 'links inline'));
      // Wrapping the terms list
      $vars['terms'] .= '<div class="vocabulary taxonomy_vid_';
      $vars['terms'] .= $vid;
      $vars['terms'] .= '">';
      $vars['terms'] .= $name;
      $vars['terms'] .= ':&nbsp;';
      $vars['terms'] .= $terms;
      $vars['terms'] .= '</div>';
    }
  }    
}

Here is what the preprocess function does essentially:

Overwriting the $terms variable with a preprocess function.

The new HTML generated from print $terms (in node.tpl.php) is shown in this Firebug screen capture:

Terms are now printed by vocabularies

This solution will work in Drupal 6 only. Of course, there's an equivalent method for Drupal 5, and if someone asks for it I will provide it.

In Drupal 5, there was a function called taxonomy_get_vocabulary($vid) .This function has been renamed in Drupal 6 to taxonomy_vocabulary_load($vid). It has been renamed probably to bring naming consistency between functions that load objects, such as node_load() and user_load(). The function returns the vocabulary object matching the vocabulary ID $vid. The vocabulary object contains 'name' and 'description' properties, both of which you can use in your theme.


CSS styling

You may need to style your terms if you want them to appear on the same line, like so (these are rules added to the Garland theme style.css file):

/**
 * Terms styling rules
 */
 
.vocabulary {
  display: inline-block;
  padding-right: 1.5em;
}
 
.terms {
  float: none;
}
Last edited by Caroline Schnapp about 6 weeks ago.

Comments

Hiding a vocabulary

You may use taxonomy for organizing your content, but may wish to NOT display terms that belong to certain vocabularies in your node. With the solution I presented, it becomes very easy to do so.

You may use CSS like so if you wish to hide terms that belong to the vocabulary with ID 4:

.terms .taxonomy_vid_4 {
  display: none;
}

Or you can decide to remove this vocabulary from your $vocabulary array in your preprocess function like so:

// We get rid of the terms that belong to vocabulary no 4
unset($vocabulary[4]);

Module?

If you'd like others to also be able to easily display their terms grouped by vocabulary, it shouldn't be too hard to implement your code into a contrib module. Especially in Drupal 6, now that you can provide .tpl.php and _preprocess theme functions along with your module, as well as some default CSS styling.

Also, note that taxonomy_get_vocabulary() was renamed to taxonomy_vocabulary_load() in Drupal 6, because the new menu system automagically calls _load functions under certain naming conditions. In this case, The D6 taxonomy module defines the menu item 'admin/content/taxonomy/edit/vocabulary/%taxonomy_vocabulary'; as such, the menu system automagically calls 'taxonomy_vocabulary_load()' (by concatenating the string after the '%' in the menu item, with the string '_load'), when the callback for editing a vocabulary is invoked.

Plus, there are cleaner ways to hide terms from a specific vocabulary, than to hard-code excluded vid's in your site's theme. As a simple alternative, you could define a variable 'taxonomy_hidden_vocabularies', which would be an array of vocabulary IDs that your theme would refer to. For a more complex approach, have a look at the category module, which (as well as a million other things) lets you hide specific vocabularies from view (using the category_display sub-module). Note that I'm the author of this module, so I'm biased - the module is big and complex, and it isn't appropriate in many situations. A simple task like hiding specific vocabularies is NOT enough reason to consider using it!!

Nope

If you'd like others to also be able to easily display their terms grouped by vocabulary, it shouldn't be too hard to implement your code into a contrib module.

In this case, a module is not the best solution. If it's not a good solution for me, I do not consider it a good solution for others. A module is overkill here. This is a tweak. The tweak takes an array that has terms flattened and give it 2 dimensions. Re-theme. Nothing more.

I am a themer just as I am a module developer. I like to show people how to leverage what they see on the page within their theme — and show them how they have full control. Using the preprocess function, it is possible to rename labels, change whether you'll put : [colon] between the label and the list, and you can also create as many variables as you have vocabularies, and print them at different locations in the node view. So you could show the tags in one location, and the terms belonging to another vocabulary somewhere else. Say you have an e-commerce/ubercart site and have faceted vocabularies, like so:

By Garment
Blouse | Skirt | Jacket | Pants
By Color
Red | Azure | Green | Ash | Beige
By Fabric
Cotton | Wool | Rayon | Silk | Linen

You may want to iconize each term based on its vocabulary: garment, or color, or fabric.

Also, note that taxonomy_get_vocabulary() was renamed to taxonomy_vocabulary_load() in Drupal 6, because the new menu system automatically calls _load functions under certain naming conditions.

So that's the reason! Thank you for the insider info.

Plus, there are cleaner ways to hide terms from a specific vocabulary, than to hard-code excluded vid's in your site's theme.

I disagree. By the way, the part about hiding a vocabulary is not the GOAL of this theming exercise. It is simply something that is facilitated... as a side effect. That's why I mention it in a comment. Creating a variable in the theme? For whom? The person who will need to modify that variable is the same person who can do unset(..) in the preprocess function. Some people ask for these tweaks: hide this link, hide this term, etc. It is entirely clean and kosher.

A simple task like hiding specific vocabularies is NOT enough reason to consider using [my module]!!

Amen.

No effect

I'm new at drupal and I've tried to add your phptemplate_preprocess_node funtion in my theme template.php file, but afterwards it takes no effect. The themes variable remains the same in node.tpl.php. I've also tried to create a new variable $vars['myterms'] but it isn't passed to node.tpl.php.

Do I miss anything? It may be some other module that interferes?

Thank you in advance.

Sorry...

Do I miss anything?

Sorry... I've missed to clear the cache... Thank you for your precious tutorials, I'm learning a lot from them.

No worries

Clearing the cache is a common thing we forget when theming Drupal 6.

Post new comment

The content of this field is kept private and will not be shown publicly.
  • Web page addresses and e-mail addresses turn into links automatically.
  • Lines and paragraphs break automatically.
  • You may post code using <code>...</code> (generic) or <?php ... ?> (highlighted PHP) tags.
  • Allowed HTML tags: <a> <b> <i> <em> <strong> <cite> <code> <ul> <ol> <li> <dl> <dt> <sup> <sub> <dd> <del> <blockquote> <img> <q> <p> <div>

More information about formatting options

CAPTCHA
This question is for testing whether you are a human visitor and to prevent automated spam submissions.
12 + 6 =
Solve this simple math problem and enter the result. E.g. for 1+3, enter 4.