Hi,

I'd like to create a block which shows a list of items related to the current node. I know how to do this in Drupal 6: views with an argument with taxonomy_node_get_terms(). However, this function does not exist in Drupal 7.

What is the correct way to get the terms associated to a node in Drupal 7?
Is there even a better way? I noticed the option "Load default argument from node page, thats good for related taxonomy blocks." for the Taxonomy: Term ID argument. However, it doesn't seem to work (the option does not get saved).

Thanks
Tim

Comments

Tim-Erwin’s picture

Well, I found a way:

$node = node_load(arg(1));
if ($node != NULL) {
$field = $node->field_my_vocabulary;
$terms_en = $field['en'];
foreach ($terms_en as $term) {
$terms[] = $term['tid'];
}
return implode('+', $terms);
}

In Drupal 7 taxonomies are stored in fields, in this example "field_my_vocabulary". This contains a language array of which each item contains the terms. It works.

What's ugly about it is the hard-coded "en" in line 4. Is there a more generic way?

flowersun’s picture

Thanks for your solution.

For the language I have tried doing the following:

$lang= $node->language;
$terms = $field[$lang];

What I don't know if it would work with multilanguage sites.. but for the sites set up for a language seems to work.

flowersun’s picture

Hi,

I checked the code you were suggesting but debugging it I realized that the data that was returned was not the same that was obtaining with the taxonomy_get_term function.
In order to get a suitable solution I modified the query that is done in the function but taking into account the new tables in Drupal 7.
This is what the query looks like:

$result = db_query(
SELECT ttd.tid, ttd.vid, ttd.name, ttd.description, ttd.weight
FROM taxonomy_term_data AS ttd
INNER JOIN taxonomy_index ti ON ti.tid = ttd.tid
WHERE ti.nid= :nid
ORDER BY ttd.weight, ttd.name',array(':nid' =>$node->nid));

Now the returned data looks like what one obtained by the function in Drupal 6.

Gaelan’s picture

If you are working in a single-language environment, substitute und for en.

Matt V.’s picture

A variation on the following worked for me, (credit goes to page 355 of Pro Drupal 7 Development):

  $nid = 2;
  $node = node_load($nid);
  $result = field_view_field('node', $node, 'field_tags', array('default'));
  print render($result);
emmeade’s picture

Matt -

What is the variation you used? This returns the rendered field with field label. How would one get just the field values? I'm trying to convert the following to D7 in order to have a related content block view:

$node=node_load(arg(1));
if($node){
foreach($node->taxonomy as $term){$terms[]=$term->tid;}
return implode('+',$terms);
}else {return;}

alienzed’s picture

ah Drupal, so easy and SO COMPLICATED!!
Here's how to get the taxonomy name; I don't know if it will work for everybody. Using the various variations of code in this thread and exhaustive foreach'ing, I found the following print statement after calling 'field_view_field':

$result = field_view_field('node', $node, 'field_tags', array('default'));
print $result['#object']->field_tags['und'][0]['taxonomy_term']->name;




I'll post the code I used to find that so that you can all get to the same solution even if your system is set up differently. Here are the steps:
1)Seeing the taxonomy name is easy:

$result = field_view_field('node', $node, 'field_tags', array('default'));
print render($result);

2) What is render doing? After the code in step 1, I printed the array to see where the name was coming from:

print_r($result);

3) A little bit much, how about this:

print_r($result['#object']);

4)Now we're getting somewhere. We only want the tags though so only look at 'field_tags' key.

foreach ($result['#object'] as $key => $field){ //looking through object
  if ($key == 'field_tags') { //ah HA! must be here somewere
     print_r($field);
     print $field['und'][0]['tid']; //there's the taxonomy ID! no name though
  }
}

5) The TID is easy to get. Now we find the name itself. There's another embedded object in there so the following code goes inside the IF statement in step 4:

foreach ($field['und'] as $term => $termInfo) { //was inside 'und', why?!
  print $termInfo['tid']; // got the ID!!
  print_r($termInfo);
}

6) Finally, we can see the name inside the 'taxonomy_term' object with a 'print_r'. Here's that foreach again, but modified to show what we are looking for.

foreach ($field['und'] as $term => $termInfo) { //was inside 'und', why?!
  print $termInfo['taxonomy_term']->name ."<br>";
}

These steps should let you see all taxonomies, but I only have one. The name is therefor inside the 'taxonomy_term', of the first array inside the 'und' key field of the field_tags array, which is inside the '#object' field of the result from field_view_field().

print $result['#object']->field_tags['und'][0]['taxonomy_term']->name;

Easy right? XD

firestonej’s picture

For anyone showing up here later and wondering what this starred comment meant:

foreach ($field['und'] as $term => $termInfo) { ***//was inside 'und', why?!***
  print $termInfo['taxonomy_term']->name ."<br>";
}

Und means "Undefined." That part of the array determines the language the site is being viewed in, since settings inside the structure might vary for different languages. Therefore, calling $field['und'] is not a very portable snippet - this code would likely fail with a multilingual site.

m.zerres’s picture

Works for me. But I want to have only the plain term name to get printed. Any idea? Thnx

Z2222’s picture

If no one else has already mentioned it, "field_tags" should be replaced with the "machine name" of the vocabulary. It can be found on the "manage fields" tab when editing the content type. If you're upgrading an older Drupal site, it might be "taxonomy_vocabulary_2" or something else.

It took me a while to figure that out, not knowing that "field_tags" is a specific vocabulary in Drupal 7 and not "print out whatever taxonomy is associated with that page" like $terms did in older versions of Drupal.

Scott J’s picture

An answer from #959984: taxonomy_node_get_terms doesn't work with drupal 7

function taxonomy_node_get_terms($node, $key = 'tid') {
static $terms;
  if (!isset($terms[$node->vid][$key])) {
    $query = db_select('taxonomy_index', 'r');
    $t_alias = $query->join('taxonomy_term_data', 't', 'r.tid = t.tid');
    $v_alias = $query->join('taxonomy_vocabulary', 'v', 't.vid = v.vid');
    $query->fields( $t_alias );
    $query->condition("r.nid", $node->nid);
    $result = $query->execute();
    $terms[$node->vid][$key] = array();
    foreach ($result as $term) {
      $terms[$node->vid][$key][$term->$key] = $term;
      }
  }
return $terms[$node->vid][$key];
}

For non-php programmers, I believe that CCK Blocks module can do this for you, but it will only display one field per block, not ALL terms for the node.

awasson’s picture

Scott,
Thanks for the update with link to that discussion. I've been struggling with this (finding terms associated with current node) in template.php for several days and was beginning to question my sanity. That discussion thread sheds a great deal of light on the issue.

Cheers,
Andrew

valderama’s picture

hi tim ;)

--

keine zeit für spielkonsolen mein leben ist jump n run!

valderama.net

trothwell’s picture

I'd love to see a reason as to why this function was removed, I can't seem to get anything to work correctly anymore. I understand taxonomy was revamped and changed a fair bit, but i'm sure the function could of been modified.

Doing such a simple task has become way to complicated and difficult it's to the point it's ridiculous.

agmin’s picture

How does the taxonomy module not support returning all terms for a node? It's kind of ridiculous that any module that wants to get the term names for a node has to manually muck through the db to grab the information. Sure all fields are automatically loaded with node_load, but in no way are they marked as being taxonomy terms.

trothwell’s picture

For anyone who is interested this can be accomplished with the use of Views and a contextual filter.

This basically will force the results to be node specific so add a contextual filter : Content: Nid.

"When the filter value is NOT in the URL"
-> Provide default value
- Type: PHP Code
- PHP contextual filter code: return arg(1);

MauHG’s picture

Thanks that work for me very well!!!

Sta5is’s picture

THANKS FOR ALL THE SOLUTIONS!
here's the version to display all the tags seperated by ',' as string stored in $tags variable.
NOTE:
i pasted the codes into my theme's node.tpl.php file
you can paste the code under your block or article body with php filters

DRUPAL 7:

$result = field_view_field('node', $node, 'field_tags', array('default'));  

$arrItems = $result['#object']->field_tags['und'];
$tags="";
$i = 0;

foreach($arrItems as $new){ 
   if( $i < count($arrItems) && $i > 0){  
          $tags .= ",";   
    }     
    $tags .= $arrItems[$i]['taxonomy_term']->name;    
    $i++;
}
print $tags;
Vali Hutchison’s picture

That's great - and this does the same thing but with a bit less PHP:

$result = field_view_field('node', $node, 'field_tags', array('default'));  
$terms = $result['#object']->field_tags['und'];
$tags = array();

foreach($terms as $term){ 
    array_push( $tags, $term['taxonomy_term']->name );    
}

print implode(',', $tags);
__andrew__’s picture

Thanks to everyone this was helpful. I found I needed a two slight variations to work in page and sidebar templates..


 // following code helps to retreive the taxomony name tags FROM region(sidebar) templates.
	$node = node_load(arg(1));
	if ($node != NULL){
	$field = $node->field_pageterms;
	$terms_und = $field['und'];
	
		foreach ($field['und'] as $term => $termInfo) { //was inside 'und', why?!
		$tagName = $termInfo['taxonomy_term']->name;
		}
	
	}

OR

// following code helps to retreive the taxomony name tags FROM PAGE templates.
$result = field_view_field('node', $node, 'field_pageterms', array('default'));

	foreach ($result['#object'] as $key => $field){ //looking through object
	if ($key == 'field_pageterms') { //ah HA! must be here somewere

	foreach ($field['und'] as $term => $termInfo) { //was inside 'und', why?!
		$sidebar = $termInfo['taxonomy_term']->name;
		}
	}
}
alan mccoll’s picture

Thank you so much alienzed and everyone! I've been searching for days. Not being a programmer, this was very difficult. I needed to print different URL Links based on the taxonomy term name from a custom node template file. This did the trick! I only have one registration page URL available now. I will change this to a 'switch' statement when I get additional landing pages for the registration. This was the code I used if anyone is interested.

<?php
$result = field_view_field('node', $node, 'field_event_type', array('default'));
foreach ($result['#object'] as $key => $field){ //looking through object
  if ($key == 'field_event_type') { //ah HA! must be here somewere
     foreach ($field['und'] as $term => $termInfo) { //was inside 'und', why?!
  $termName = $termInfo['taxonomy_term']->name;
  if($termName=="Awana Ministry Conference")
  print "<div class='easy-reg'><a href='https://www.easyreg.org/cgi-bin/easyreg/registrationdbase/WDT9IXKY5N/signup.pl'>Register Online</a></div>";
    }
  }
}
 ?>
aembke’s picture

Here's a simple way to iterate over the tags in a node.

    $tags = field_view_field('node', $node, 'field_tags', array('default'));
    foreach($tags["#items"] as $tag){
        $name = $tag["taxonomy_term"]->name;
        // do stuff
    }

Hope that helps.

jkurrle’s picture

This may not be the preferred way to get taxonomy terms, but I've done it this way before:

//preset tags and facets (vocabularies) to empty arrays
$tagsArr = array();
$facetsArr = array();

// load the node
$node = node_load(arg(1));

//if it is a node, then do the following:
if ($node != NULL) 
  {
  // query to get taxonomy terms and the vocabularies they are in
  $result = db_query('SELECT  a.name as taxKey,b.name as taxVoc
                      FROM    {taxonomy_term_data} a, {taxonomy_vocabulary} b, {taxonomy_index} c
                      WHERE   c.tid = a.tid
                      AND     a.vid = b.vid
                      AND     c.nid = :nid', array(':nid' => $node->nid));

  //Append each key and facet into their respective arrays
  while ($record = $result->fetchAssoc())
    {
    $tagsArr[] = $record['taxKey'];
    $facetsArr[] = $record['taxVoc'];
    } // end while ($record = $result->fetchAssoc())

  //imploding arrays into variables
  $tags = implode(", ",$tagsArr);
  $facets = implode(", ",$facetsArr);
  } // end if ($node != NULL) 

This creates two variables: $tags, which is a comma delimited list of tags and $facets, which is a comma delimited list of respective vocabularies.

Michele Wickham’s picture

I know it's a bit late of a reply on this, but I had a similar problem in that I had the node object but needed all of its taxonomy ids to pass into a view result - I took this approach as it does not require mucking about with language settings or markup:

            /* four taxonomy fields */
            $geo = field_get_items('node', $node, 'field_geography');
            $programs = field_get_items('node', $node, 'field_programs');
            $roles = field_get_items('node', $node, 'field_roles');
            $sectors = field_get_items('node', $node, 'field_taxonomy');

            /* merge the arrays into one */
            $all = array_merge($geo, $programs,$roles,$sectors);

            /* gather just the tids into an array */
            $tid = array();
            foreach($all as $item) {
                $tid[] = $item['tid'];
            }
            $tids = implode(',', $tid);

            $view = views_get_view('news');
            $view->set_display('block_1');
            $args = array(
                0 => $tids,
                1 => $node->nid,
            );
            $view->set_arguments($args);
            ...

No SQL required and no language issues.

alberto56’s picture

Here is a generic function that does this:

/**
 * Helper function to get taxonomy terms related to a node.
 *
 * See https://drupal.org/node/909968
 *
 * @param $node
 *   A node object
 *
 * @return
 *   An associative array in the following format:
 *   array(
 *     field_name => array(
 *       TID => name
 *       TID => name
 *     ),
 *     field_name_2 => array(
 *     )
 *   )
 */
function MYMODULE_taxonomy_terms($node) {
  $return = array();
  if (is_object($node)) {
    // get all fields for the given node type
    $fields = field_info_instances('node', $node->type);
    foreach ($fields as $fieldname => $info) {
      // check if fields are taxonomy terms
      if ($info['widget']['module'] == 'taxonomy') {
        $return[$fieldname] = array();
        // if they are, load all term names and tids for given field
        foreach (field_get_items('node', $node, $fieldname) as $field) {
          $term = taxonomy_term_load($field['tid']);
          $return[$fieldname][$field['tid']] = $term->name;
        }
      }
    }
  }
  return $return;
}

Cheers,

Albert

Tim-Erwin’s picture

Three years and this is still an issue... With entities and fields drupal has become very compley, IMHO. Thanks for this clean solution, Albert!

BetoAveiga’s picture

Thanks @Alberto56 for the code. Definitely smart code but there are modules othen than "taxonomy" that handle taxonomy fields. Like "term_reference_tree".

So modify this line...
if ($info['widget']['module'] == 'taxonomy') {

With this line... (and for everybody pay attention if some other module is handling taxonomy fields)

if ( in_array ( $info['widget']['module'], array ('term_reference_tree', 'taxonomy' ) ) ) {

Hope that helps!

Drupal Backend / Frontend Developer

gisle’s picture

The function MYMODULE_taxonomy_terms($node) provided by alberto56 works if the widget used to populate an taxonomy field is of the autocomplete kind.

Unfortunately, not only does it miss taxonomy terms handled by fairly specific widgets such as term_reference_tree, it fails to spot taxonomy terms that are selected by means such as radio buttons and checkboxes. These widgets are also used by fields that are not taxonomy terms, so scanning for them may produce false positives.

Most other solutions posted here are even less general, and assumes the name of the field associated with the vocabulary (e.g. field_tags) is known.

Still looking for a generic solution.

- gisle

ronnbot’s picture

Here's a very generic way to grab all terms without specifying field names and no db_query:

    function example_get_terms($node) {
      $terms = array();

      foreach (field_info_instances('node', $node->type) as $fieldname => $info) {
        foreach (field_get_items('node', $node, $fieldname) as $item) {
          if (is_array($item) && !empty($item['tid']) && $term = taxonomy_term_load($item['tid'])) {
            $terms[] = $term->name;
          }
        }
      }
      return $terms;
    }
jiaxin’s picture

here is another simple way to get taxonomy terms name or id related to the current node.

$node = menu_get_object();
$result = $node ->field_tags['und'][0]['taxonomy_term'];
$taxonomy_name = $result -> name;
$taxonomy_vid = $result -> vid;

that's it!