Create comma-separated taxonomy term list in Drupal

I was wondering how to create a comma-separated taxonomy term list per node, because the default space-separated list is confusing for terms containing spaces (I only use a few but still). I temporarily solved it with CSS by adding a visual separation with a background image for all but the first terms. In honesty, it worked but it looked rather clunky.

/* Taxonomy terms */
.tags li {
  background: transparent url(img/dot.png) no-repeat left center;
  padding-left: 19px; /*leave any top/bottom padding*/
  padding-right: 0px;
  margin-left: 0px; /*leave any top/bottom margin*/
  margin-right: 0px;
}
.tags li.first {
  background: none !important;
  padding-left: 0 !important;
}

Until I stumbled upon a 2008 post at Kobashi Computing in which the author accomplishes exactly what I was looking for.

<?php
function phptemplate_preprocess_node(&$vars) {

 
// Taxonomy hook to show comma-separated terms
 
if (module_exists('taxonomy')) {
   
$vars['term_links'] = '';
   
$count = 1;
   
$term_links = taxonomy_link('taxonomy terms', $vars['node']);
   
$numcount = count($term_links);
    if (
$numcount > 0) {
      foreach (
$term_links as $link_item) {
       
$vars['term_links'] .= l($link_item['title'], $link_item['href'], $link_item);
        if (
$count < $numcount)
         
$vars['term_links'] .= ', ';
       
$count++;
      }
    }
  }

}
?>

Thanks for sharing this great code snippet.

In your node templates you can still test if there are taxonomy terms available for the node by using <?php if ($terms) { ... } ?> and then instead of using <?php print $terms; ?> you use the newly defined <?php print $term_links; ?>.

Compacter solution

And then based on the code found at gerardmcgarry.com you could come up with the following code for the template.php.

<?php
function phptemplate_preprocess_node(&$vars) {

 
// Taxonomy hook to show comma separated terms
 
if (module_exists('taxonomy')) {
   
$term_links = array();
    foreach (
$vars['node']->taxonomy as $term) {
     
$term_links[] = l($term->name, 'taxonomy/term/' . $term->tid,
        array(
         
'attributes' => array(
           
'title' => $term->description
       
)));
    }
   
$vars['node_terms'] = implode(', ', $term_links);
  }

}
?>

I like the use of implode() — see php.net for the syntax.

Just use <?php print $node_terms; ?> in the node template to display the terms. Of course, test for the existence of terms first, like in the previous example.

<?php if ($terms) { ?>
  <div class="tags">
    <span><?php print t('Tags: '); ?></span><?php print $node_terms; ?>
  </div>
<?php } ?>

Too bad that this is not optional in Drupal.

Comments

Just wanted to say thanks! I was having trouble with this, and your solution solved it.

I posted a solution to this problem some time ago on my Drupal Blog - http://oliverdavies.co.uk/2010/04/05/sty...

Is there any way of outputting the url links as lowercase, but keeping the printed list normal?

In other words:
Term name -> term name
Business -> business

Thus you would get a list of:

Business, Entertainment, Leisure

that has the url paths:

business, entertainment, leisure

Found my answer. Edit:

$term_links[] = l($term->name, 'category/' . $term->name,

to

$term_links[] = l($term->name, 'category/' . strtolower($term->name),

Thanks for taking the time to post your solution.

hi, thanks for the snippet. i'm struggling with a modification to this to allow display of links on a per-vocabulary basis, ala http://timonweb.com/how-to-separate-drupal-taxonomy-terms-output-by-vocabulary

can you offer any advice?

There is an easy example at Drupal: Display taxonomy terms broken out by vocabulary:

<?php
function yourthemename_print_terms($node, $vid = NULL, $ordered_list = TRUE) {
    
$vocabularies = taxonomy_get_vocabularies();
     if (
$ordered_list) $output .= '<ul>'; //checks to see if you want an ordered list
    
if ($vid) { //checks to see if you've passed a number with vid, prints just that vid
       
$output = '<div class="tags-'. $vid . '">';
        foreach(
$vocabularies as $vocabulary) {
         if (
$vocabulary->vid == $vid) {
          
$terms = taxonomy_node_get_terms_by_vocabulary($node, $vocabulary->vid);
           if (
$terms) {
            
$links = array();
            
$output .= '<span class="only-vocabulary-'. $vocabulary->vid . '">';
             if (
$ordered_list) $output .= '<li class="vocabulary-'. $vocabulary->vid . '">' . $vocabulary->name . ': ';
             foreach (
$terms as $term) {
              
$links[] = '<span class="term-' . $term->tid . '">' . l($term->name, taxonomy_term_path($term), array('rel' => 'tag', 'title' => strip_tags($term->description))) .'</span>';
             }
            
$output .= implode(', ', $links);
             if (
$ordered_list) $output .= '</li>';
            
$output .= '</span>';
           }
         }
       }
     }
     else {
      
$output = '<div class="tags">';
       foreach(
$vocabularies as $vocabulary) {
         if (
$vocabularies) {
          
$terms = taxonomy_node_get_terms_by_vocabulary($node, $vocabulary->vid);
           if (
$terms) {
            
$links = array();
            
$output .= '<ul class="vocabulary-'. $vocabulary->vid . '">';
             if (
$ordered_list) $output .= '<li class="vocabulary-'. $vocabulary->vid . '">' . $vocabulary->name . ': ';
             foreach (
$terms as $term) {
              
$links[] = '<span class="term-' . $term->tid . '">' . l($term->name, taxonomy_term_path($term), array('rel' => 'tag', 'title' => strip_tags($term->description))) .'</span>';
             }
            
$output .= implode(', ', $links);
             if (
$ordered_list) $output .= '</li>';
            
$output .= '</ul>';
           }
         }
       }
     }
     if (
$ordered_list) $output .= '</ul>';
    
$output .= '</div>';
     return
$output;
}
?>

This code needs some cleaning up since it violates the Drupal coding standard but it does the job. As per the example:

  • Make sure the function resides in template.php and rename it to something suitable.
  • In your node template, call the function with <?php print yourthemename_print_terms($node, $vid = NULL, $unordered_list = TRUE); ?>.

It then returns the terms as a comma-separated list per vocabulary.

Works grate!
Thank you...

Works grate!
Thank you...

totally awesome !