Programmatically Adding or Removing a User or Node Reference from a Node (D7 / References)

The References module in Drupal 7 allows for easy creation and removal of user and node references through Drupal's interface. However, programmatically adding and removing these references is a little more difficult.

You basically have to load the node which has the reference in it, edit the reference field (in my example, the reference field can have an unlimited number of references), add or remove the user ID (or node ID if you're chaging a node reference), and save the node.

Let's look at the example of simply adding a user reference to a node:

<?php
 
// Load the node you'd like to edit.
 
$node = node_load($nid);
 
// Add the user ID you'd like to add to this node reference.
 
$node->field_node_user_references[$node->language][] = array('uid' => $uid);
 
// Save the node.
 
node_save($node);
?>

It takes a little more effort to remove a user reference (or node reference) from a node. For this, since I have to do it for a few different fields on a node, I've written a helper function that removes a given $uid from the array of user references on a given node.

Code first, explanation after:

<?php
/**
 * Helper function to remove an user reference by value.
 */
function _MYMODULE_remove_user_reference_by_uid($reference_field_lang_array, $uid = '', $preserve_keys = FALSE) {
 
// Since we have a multi-value user reference field, we need to check each value.
 
foreach($reference_field_lang_array as $key => $value) {
    if (
$value['uid'] == $uid) {
     
// If the user ID is found in the array, unset that value.
     
unset($reference_field_lang_array[$key]);
    }
  }
 
// Run this through array_values() so the array index (0, 1, 2, etc.) is reset.
 
return array_values($reference_field_lang_array);
}
?>

To call this function and actually remove a given user from the user reference field, we'll do something like the following:

<?php
 
// Load the node you'd like to edit.
 
$node = node_load($nid);
 
// Use our helper function to remove the given user id from the references field.
 
$list->field_node_user_references[$list->language] = _fn_networks_remove_user_reference_by_uid($node->field_node_user_references[$list->language], $uid);
 
// Save the node.
 
node_save($node);
?>

It's slightly convoluted, sure, but it really helps if you, like me, need to build an alternate interface for allowing, say, list administrators to quickly add or remove a user reference from a list. In my case, I use this feature to let list administrators for a site toggle list subscribers from being able to add posts to a given list.

Adding and removing node references would be about the same, but you would use whatever field name you have for your node reference.

P.S. The Relation module for Drupal 7 looks like it might someday replace references, but for now, it's not nearly as supported/simple to use... at least in my book!

Comments

No need to do the foreach, you can use array_search(). Nor are you using $preserve_keys. You will also have a PHP error if the uid is not found. So you can simplify the function to:

<?php
/**
* Helper function to remove an user reference by value.
*/
function _MYMODULE_remove_user_reference_by_uid($reference_field_lang_array, $uid) {
 
$key = array_search($uid, $reference_field_lang_array);
  if (
$key !== FALSE) {
    unset(
$reference_field_lang_array[$key]);
  }

 
// Run this through array_values() so the deltas are reset.
 
return array_values($reference_field_lang_array);
}
?>

Hi,
I came here because I want I have a Content Type with a user reference and I want to set it programmatically

I'm foxed by this line of code, despite the fact I understand the individual syntax

<?php
  $node
->field_node_user_references[$node->language][] = array('uid' => $uid);
?>

  • $node->field reference between an object and an attribute
  • [][] nested array content
  • array('uid' => $uid) creating an array with one key 'uid' with a value of $uid

What's the purpose of this $node->language ?

Where did the $uid come from? Are we supposed to have it already?

How to understand these object attributes containing nested arrays being given array values? Is there anywhere I can go to understand this kind of thing?

In Drupal 7, you need to specify the language of a field, and I elect to do so using $node->language... You can sometimes use 'und' as that value, or LANGUAGE_NONE (constant of 'und'), but $node->language seems more future proof to me.

Also, the $uid should be provided to the function to remove the user...

If you want to programmatically add a user reference to a node, then it's a bit simpler... just add the uid to the array using similar syntax...

Thanks for the answer, Jeff.
For people in the same predicament as I was yesterday: since posting my puzzled comment, I found a way of mastering the complexity of those nested arrays + attributes. By using the Devel module, you get a map of the data structure of a node (in the Devel tab, added in to the right of the Edit tab when you activate the module).
Once you are there, you see a tree representing the data structure. If you then want to access or edit that data in your php code:
* any time you see stdclass you put in a -> sign,
* every time you see an Array(XXX) you put [XXX]
* check out how to save the node once you have finished
You can also use
print_r('<pre>'. $myComplexDurpalObject . '<pre>' , TRUE);

Using this method, I now successfully entered lines of code such as this one:

<?php
// get the node
// create a node
$node = new stdClass();
$node->name = $user->name;

$_i=0;
// cycle through a list of users
foreach($_usersList as $_user){
   
// ************* THIS IS WHERE THE STRUCTURE OF NODES AND USERS (COMING FROM THE DEVEL MODULE AND PRINT_R) IS USED
   
$userid = $_user[user]->uid;
   
$node->field_myfieldname[$_i ]['uid'] =  $userid;
   
$_i++;
....
// retrieve the node_save function
 
if( ! function_exists("node_object_prepare")) {
      include_once(
drupal_get_path('module', 'node') . '/node.pages.inc');
   }
// save the node
if ($node = node_submit($node)) node_save($node);
?>

that previously had me completely foxed

Additionally, if you simply use something like dpm($node); with Devel module enabled, you will see the full node object in a hierarchical view in the messages area.

Sorry the example got jumbled, no way of editing it after posting...

Excellent post!. Can you please provide an example using a node reference by node ID, instead of a user reference?

I'll have to leave that up to you; the structure should be almost exactly the same. If you use the Devel module, you could inspect the node object and see exactly how the data is structured for a node reference by visiting the node page and clicking the 'Devel' tab...

->i have created a content type and dded a cck field user reference in which all the users are listed.
->In views i have selected this user reference field, it display's all the selected users for the particular node it's fine.
->if i choose the GLOBAL:PHP field and print the user reference $row->field_user_reference from the available variable, instead of printing the selected user's it give node id.
->And after manually inserting into the users reference table no update on the views selected field.
->can any one explan me how to insert the data into cck user reference table,and else where it get's stored.

please help me out............