7.x node.api.php hook_node_presave($node)

Act on a node being inserted or updated.

This hook is invoked from node_save() before the node is saved to the database.


$node: The node that is being inserted or updated.

Related topics

5 functions implement hook_node_presave()

Note: this list is generated by pattern matching, so it may include some functions that are not actually implementations of this hook.

book_node_presave in modules/book/book.module
Implements hook_node_presave().
entity_crud_hook_test_node_presave in modules/simpletest/tests/entity_crud_hook_test.module
Implements hook_node_presave().
forum_node_presave in modules/forum/forum.module
Implements hook_node_presave().
node_test_node_presave in modules/node/tests/node_test.module
Implements hook_node_presave().
trigger_node_presave in modules/trigger/trigger.module
Implements hook_node_presave().
3 invocations of hook_node_presave()
field_attach_presave in modules/field/field.attach.inc
Perform necessary operations just before fields data get saved.
node_save in modules/node/node.module
Saves changes to a node or adds a new node.
user_save in modules/user/user.module
Save changes to a user account or add a new user.


modules/node/node.api.php, line 687
Hooks provided by the Node module.


function hook_node_presave($node) {
  if ($node->nid && $node->moderate) {
    // Reset votes when node is updated:
    $node->score = 0;
    $node->users = '';
    $node->votes = 0;


torotil’s picture

You can access the original contents of the node at:

aaronbauman’s picture

maybe it's obvious, but $node->original will not exist for inserts.

TanvirAhmad’s picture

How can I access original content in hook_node_validate. I want to through an error if value of a checkbox is newly selected. i-e shouldnt through error if already selected.

liquidcms’s picture

is there a way to prevent saving the node? (can't do form validate as this is not necessarily done on form submit)

jason.fisher’s picture

A drupal_goto would probably short-circuit the save?

ExTexan’s picture

What about other module hooks that may have fired before *your* module that already acted on the node - possibly adding linked records in other tables? Using drupal_goto could leave orphaned records or a mismatched condition between fields in the node and data in other tables.

brian_c’s picture

You'd probably need to get at it well before it reaches hook_presave().

Try using hook_form_alter() to intercept the node form, and changing $form['actions']['submit']['#submit'][0] from node_form_submit to a custom function that can then do whatever you want with the node submission (including conditionally passing it off to node_form_submit() if you DO want it saved).

Note that bypassing the normal node_form_submit() will mean that NOTHING happens, not even returning you to the node view (you'll just land on the edit form again) so if you want that to happen you'll need to do it yourself (look to node_form_submit() for details on how to accomplish any of the normal actions.)

Here's an example that would prevent saving of a node:

function MODULE_form_alter(&$form, &$form_state, $form_id){
  if( $form_id == 'CONTENTTYPE_node_form' ){
    $form['actions']['submit']['#submit'][0] = 'MODULE_my_custom_submit_handler';
function MODULE_my_custom_submit_handler($form, &$form_state){
  // do nothing.. or something...
texas-bronius’s picture

Right on @brian_c. I'd like to point out to the uninitiated that you're definitely saying *replace* the submit handler that was provided by the node module out of the box as opposed to *appending* or prepending an additional submit handler. Forms API processes all submit handlers specified in the order on the ['#submit'] array, and node module gets its vote, too, unless replaced as in that example. The difference is in the assignment:

/** Replace **/
$form['actions']['submit']['#submit'][0] = 'MODULE_my_custom_submit_handler';
/** Append **/
$form['actions']['submit']['#submit'][] = 'MODULE_my_custom_submit_handler';
/** Prepend **/
$form['actions']['submit']['#submit'] = array_unshift($form['actions']['submit']['#submit'], 'MODULE_my_custom_submit_handler');
Andrew Le Conte’s picture

Don't use drupal_goto() if you're importing multiple nodes. If you're using something like Feeds it will cause problems and prevent subsequent nodes from importing. Instead just thrown an error during presave, i.e.:

function mymodule_node_presave($node){
    throw new Exception('Error saving node: Title cannot be empty');

The node_save() function has a try...catch block wrapping the presave step that will catch the exception. Any further processes will continue as normal, such as saving the next node.

jusfeel’s picture

The right way should be using hook_node_validate if you mean to prevent.

Garrett Albright’s picture

A cool thing about this hook is that it fires both on node save and node update, so if you need to do something both on the creation and the updating of a node, in most cases you can just implement this hook instead of separate hook_node_insert() and hook_node_update() implementations. (Just be aware this hook fires earlier in the node saving process than the other two - consult the code of node_save() if it might make a difference in your case.)

fonsv@ndamme.be’s picture

Simple example of the use of this hook to force first char to uppercase

* Implementation of hook_node_presave().

function CUSTOM_MODULE_node_presave($node) {
    $node->title = ucfirst($node->title);
Serris’s picture

why not do this through CSS? if you put this function on an existing site, you'd have to go through all the old nodes to update their titles as well.

CSS works on everything and when you decide it's no longer wanted, you still have the original casing.

massiws’s picture

This works well:

function mymodule_node_presave() {
  $var = $node->original->field_my_field['und'][0]['value'];
  if ($var == 'something') {do_something();}

I would like to access original property with Entity Metadata Wrapper, like explained in entity_test.module:

function mymodule_node_presave() {
  $wrap = entity_metadata_wrapper('node', $node);
  $var = $wrap->original->field_my_field->value();
  if ($var == 'something') {do_something();}

but I get this error:

EntityMetadataWrapperException: Unknown data property original. in EntityStructureWrapper->getPropertyInfo()

Some suggestions?

hoosierdrupalguy’s picture

I haven't tested this, but you might want to try something like this.

function mymodule_node_presave($node) {
  $original = $node->original;
  $wrap = entity_metadata_wrapper('node', $original);
  $var = $wrap->field_my_field->value();
  if ($var == 'something') {do_something();}
sinasalek’s picture

Currently Drupal core does not offer any hook to do actions after a node/entity is inserted/updated/deleted in Database. So for example you can not send an email mentioning the node after the node is inserted because Drupal uses SQL transactions and the node is not yet fully written to database when hook node presave is called so if for any reason the transaction is rolled back, users will receive a false mail.

So Hook Post Action module introduces several new Drupal hooks to overcome this limitation:
- hook_entity_postsave
- hook_entity_postinsert
- hook_entity_postupdate
- hook_entity_postdelete
- hook_node_postsave
- hook_node_postinsert
- hook_node_postupdate
- hook_node_postdelete


nithinkolekar’s picture

Could this hook can be used as alternative to computed field? are they both same in functionality?
This is just for informative purpose for choosing best one when required.

krknth’s picture

Use $node->is_new, if you want to do any functionality after node being inserted

function MYMODULE_node_presave($node) {
  if ($node->type =='page' && $node->is_new) {
    // Alter title, add time stamp at the end of title:
    $node->title = $node->title.'  '.date('M j Y h:i A');
jomarocas’s picture

for me no working good.
when i created a new node, i see that this changes in the new node no make property, im using dpm and no working good.

this is my code

 * Implements hook_node_presave().
function core_custom_forms_node_presave($node) {
   *if ($node->nid && $node->moderate) {
   *  // Reset votes when node is updated:
   *  $node->score = 0;
   *  $node->users = '';
   *  $node->votes = 0;
  if (isset($node->field_semaforo) && !empty($node->field_semaforo)) {
    $node->field_semaforo['und'][0]['tid'] = (string) 13369;

in the dpm node the changes make successful but
later of this i make dpm in form state to see values that i change but no change nothing. what happen?