Last updated June 3, 2010. Created on June 3, 2010.
Edited by Itangalo. Log in to edit this page.

Attached is a Feature and alternatively a Rules export that copies taxonomy any terms from a story node to a referenced node.

The example was inspired by a discussion in the Rules group.

Some details:

* The function is put in a rule set, to make it more flexible (and callable from other parts of Drupal). The rule set takes the source node as argument.
* The rule set is in the example called by a rule, triggering on node save (for stories only). It could also be called from Views Bulk Operations or, say, Rules Scheduler.
* The rule set copies any taxonomy terms, regardless of vocabularies. To make it vocabulary sensitive, you'll have to add a condition in the PHP code that copies the terms.
* Yeah, PHP code. Sorry about that. The modify taxonomy terms action didn't take any tokens, so PHP it was. It also turned out that the action didn't take PHP, so it is all wrapped in a "Execute arbitrary PHP code" action. I use it as last resort, and it seemed necessary here. (Please let me know if you have another solution!)

Good luck! Please post questions in the Rules discussion group.
//Johan Falk, NodeOne, Sweden

Looking for support? Visit the Drupal.org forums, or join #drupal-support in IRC.

Comments

jason.fisher’s picture

A PHP snippet that does the reverse--when a node that has references to other nodes is saved, the parent is given the merged terms of all of its children. The children are not modified.

In this example, field_child_ref should be changed to the appropriate CCK nodereference field. This code is specifically for the unlimited values field setting on the nodereference field. YMMV.

<?php
// Loop through referenced nodes
foreach ($node->field_child_ref as $delta => $ref) {
 
$ref_node = node_load($ref['nid']);
 
// Loop through all referenced node terms
 
foreach ($ref_node->taxonomy as $tid => $termdata) {
    if (!isset(
$node->taxonomy[$tid])) {
     
$node->taxonomy[$tid] = $termdata;
    } 
  }
 
drupal_set_message(t('Added terms from %ref_title to %title.', array('%ref_title' => $ref_node->title, '%title' => $node->title)));
}

// Tell Rules to save the variable $node
return array("node" => $node);
?>

Jason Fisher

tobiberlin’s picture

Just wanted to thank you for this features!!!!!!! Saved me from hours of work :)

Drupal developer and project manager from Berlin - http://www.cherry-webprojekte.de

upupax’s picture

The rule you suggested didn't work for me.

foreach ($node->taxonomy as $tid => $termdata) {

  // If the term isn\'t already present in target node, add it
  if (!isset($referenced_node->taxonomy[$tid])) {
    $referenced_node->taxonomy[$tid] = $termdata;
  }
}

Checking inside the $node->taxonomy i get this array

Array ( [4] => 6 [tags] => Array ( [1] => [5] => ) )

where 4 and 'tags' are something related to vocabulary and not to $tid.
I don't really know why the $referenced_node output is different from the Devel output of the same node, but it actually is, so I need a workaround to make the code working.
I solved like this:

// Loop through all taxonomy terms in the source node
foreach ($node_terms as $some_voc => $tid) {

  // If $tid is not an array
  if(!is_array($tid)){

  // If the term isn't already present in target node, add it
    if (!isset($referenced_node->taxonomy[$tid])) {
      $referenced_node->taxonomy[$tid] = $termdata;
    }
  }
}

As you said, additionals controls could be done to check the vocabulary before add the terms.
I made my controls just to prevent the 'tags' error.

Hope it helps.

itamair’s picture

I would need to implement this functionalities on a Drupal 7 site.
Would this code work on a Drupal 7 site, too?
How should I implement it?
Just copying and activating the "copy_taxonomy_terms_to_a_referenced_node" folder as a module?
Do I need the Features Module activated?

I guess I would adapt the code to my specific needs ...
The node type would be "Article" in which there is a reference to a "Section" node content type.
Both of them have a Category field that is takes terms from a Category vocabulary.
When I save an Article it has to inherit its Section Category Terms, at least ...

Thanks!

gittosj’s picture

Drupal 7 solution. Use case is that the parent user inherits all the terms of the child users referenced through entity_reference. At the moment I'm running this as a block include for testing so will tweak slightly for use in a rule. I'm controlling permissions through TAC so the parent user inherits permissions of all children:

<?php
$uid
=arg(1); //check the user form the url
$account = user_load($uid);
//dpm ($account); //uncomment to see krumo output of full user array
$childtags=array();
$children=$account->field_child_ren_['und']; //load the referenced child users
//dpm ($children); //uncomment to see krumo output of full children array
foreach($children as $child){ //loop through children and load tags
   
$tags = $child['entity']->field_permission_tags['und'];
   
$childtags=array_merge_recursive((array)$childtags, (array)$tags); //merge the tags for n children
   
}  
$childtags=array_map("unserialize", array_unique(array_map("serialize", $childtags))); //dedupe the array of tags
$account->field_permission_tags=array(
       
'und' => array(),
        ); 
$account->field_permission_tags['und']=$childtags; //save the tag array to the parent user

user_save($account); //save the parent user
?>
gittosj’s picture

So after a lot of tweaking - this code fires on event: user is updated

<?php
$childtags
=array();
$children=$account->field_child_ren_['und'];
foreach(
$children as $key=>$child){
  
$childuser=user_load($child['target_id']);
  
$tags = $childuser->field_permission_tags['und'];
  
$childtags=array_merge_recursive((array)$childtags, (array)$tags);
   }  
$childtags=array_map("unserialize", array_unique(array_map("serialize", $childtags)));
$edituser=(array) $account;
$edituser['field_permission_tags']=array(
       
'und' => array(),
        ); 
$edituser['field_permission_tags']['und']=$childtags;
user_save($account,$edituser);
?>
<?php
$childtags
=array();
$children=$account->field_child_ren_['und'];
foreach(
$children as $key=>$child){
  
$childuser=user_load($child['target_id']);
  
$tags = $childuser->field_permission_tags['und'];
  
$childtags=array_merge_recursive((array)$childtags, (array)$tags);
   }  
$childtags=array_map("unserialize", array_unique(array_map("serialize", $childtags)));
$edituser=(array) $account;
$edituser['field_permission_tags']=array(
       
'und' => array(),
        ); 
$edituser['field_permission_tags']['und']=$childtags;
user_save($account,$edituser);
?>

And all working fine - still need to work out whether this works on a new user si saved but time for bed.