13

Currently trying to update a field every time a node is created or updated. However the value is not being populated within the node, do I have access to the node object with this particular hook? What could I be missing?

  function vbtoken_node_update($node) {


      entity_get_controller('node')->resetCache(array($node->nid));


      $types = node_type_get_types(); //What are the current Node Content Types?
      $yes = ($types['volunteer_project']->type);

      if($node->type === $yes){


        $hash = md5($node->title . $node->nid . $node->nid);
        $hashed = substr($hash, 0, 6);
        $node = node_load($node->nid);
        $node->tcode[$node->language][0]['value'] = $hashed;
        node_save($node);

        watchdog('vbtoken', 'Added a new Token code to %nid', array('%nid' => $node->nid));

        }
        else 
        {
          dpm('not working dude');
        }

    }

4 Answers 4

16

Entity metadata wrappers

The entity API provides some wrapper classes you may use to easily deal with entities and to leverage the entity property information modules provided. With the help of the wrappers you can access the property information, loop over known properties, or just get/set the described data values, etc.

These are some simple usage examples as found in the README:

For making use of this information (metadata) the module provides some wrapper classes which ease getting and setting values. The wrapper supports chained usage for retrieving wrappers of entity properties, e.g. to get a node author's mail address one could use:

$wrapper = entity_metadata_wrapper('node', $node);
$wrapper->author->mail->value();

To update the user's mail address one could use

$wrapper->author->mail->set('[email protected]');

or

$wrapper->author->mail = '[email protected]';

The wrappers always return the data as described in the property information, which may be retrieved directly via entity_get_property_info() or from the wrapper:

$mail_info = $wrapper->author->mail->info();

In order to force getting a textual value sanitized for output one can use, e.g.

$wrapper->title->value(array('sanitize' => TRUE));

to get the sanitized node title. When a property is already returned sanitized by default, like the node body, one possibly wants to get the not-sanitized data as it would appear in a browser for other use-cases. To do so one can enable the 'decode' option, which ensures for any sanitized data the tags are stripped and HTML entities are decoded before the property is returned:

$wrapper->body->value->value(array('decode' => TRUE));

That way one always gets the data as shown to the user. However if you really want to get the raw, unprocessed value, even for sanitized textual data, you can do so via:

$wrapper->body->value->raw();

More examples:

$wrapper->body->set(array('value' => "content"));
$wrapper->field_text[0] = 'the text';
$wrapper->field_text[0]->set(array('value' => "content"));
$wrapper->field_text2->summary = 'the summary';
$wrapper->field_text2->value = 'the text';

$wrapper->save();
$wrapper->delete();

More docs: http://drupal.org/node/1021556

2
  • Thank you so much. Your answer helped give me some direction to what i had to do. :) Community rocks!! \m/
    – SGhosh
    May 22, 2014 at 11:42
  • This will work on hook_node_update but not on hook_node_insert(). You will get a duplicate primary key error from mysql, as both the node module and your custom code will be trying to insert the same node twice (using the same node id).
    – leon.nk
    May 1, 2015 at 9:48
14

Calling field_attach_update('node', $node) at the end of hook_node_update worked for me. I assume that field_attach_insert('node', $node) at the end of hook_node_insert would work, too. So, a sample function would look like this:

function mymodule_node_update($node) {
  $new_value = // ...do some stuff to compute a new value for the field.
  $node->field_my_field[LANGUAGE_NONE][0]['value'] = $new_value;
  field_attach_update('node', $node);
}

There's no need to call node_load node_save or to return anything.

I think the reason for this is that node_save, from which hook_node_update and hook_node_insert are called, wraps all database queries in a transaction. (Note the first line of node_save: $transaction = db_transaction().) These queries aren't called until node_save finishes. The last query that node_save adds to the transaction is called from field_attach_update, which uses the $node object as it is before hook_node_update is called. So you need to queue up another query by calling field_attach_update again. At least, that's my understanding of what's going on.

If you're having trouble changing non-field attributes of the node (e.g., $node->log), try calling _node_save_revision($node, $user->uid, 'vid'); too. This won't create a new revision.

2

This is how you change values on a node:

$node = node_load($nodeID);
$node->field_fieldname['und'][0]['value'] = $val;
node_save($node);
5
  • 4
    und is not really appropriate here, OP has already stated in code that they're using $node->language for the language code
    – Clive
    Jan 30, 2012 at 10:20
  • That's super helpful thanks Clive and Lance, but I want to make sure the field value is saved whenever the node is saved, hence my use of hook_node_update. Would it be possible to return the $node in this hook or do I absolutely have to do a node_load? I really thought I had the node object passed directly in through hook_node_update.... Jan 30, 2012 at 21:18
  • Ok so I updated the code as per your recommendation -- it's in the original body. Problem: Endless loop in which the page does not load and both mysql and apache start to hit upwards of 85% load on cpu. Definitely there is some looping going on here. Any other suggestions? Jan 31, 2012 at 3:57
  • I can't tell you whats going on. But probably you try once to just load the node, enter something in the field and save it using node_save(). Or just load, print something (using watchdog or dpm() and save it again to see if this works.
    – Lance
    Jan 31, 2012 at 7:46
  • The issue was derived from having saved the node before saving it resulting in a recursive loop. Poor hook choice and poor build Feb 23, 2012 at 3:33
2

An improvement of Lance's solution above, avoiding the saving of a whole node when only a few field values are modified :

$node = node_load($nodeID);
// for each field whose value remains unchanged
unset($node->field_<field-name>); 
// for each field whose value changes
$node->field_<field-name>[LANGUAGE_NONE][0]['value'] = <new-value>;
field_attach_update('node', $node);
entity_get_controller('node')->resetCache(array($node->nid));

This could also be useful to avoid side effects of node_save().

Source : Saving node's fields without saving the node itself

https://www.urbaninsight.com/2011/10/24/saving-nodes-fields-without-saving-node-itself

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.