Community Documentation

node_save

5 node.module node_save(&$node)
6 node.module node_save(&$node)
7 node.module node_save($node)
8 node.module node_save($node)

Save changes to a node or add a new node.

Parameters

$node: The $node object to be saved. If $node->nid is omitted (or $node->is_new is TRUE), a new node will be added.

▾ 19 functions call node_save()

book_admin_edit_submit in modules/book/book.admin.inc
Handle submission of the book administrative page form.
CommentInterfaceTest::setEnvironment in modules/comment/comment.test
Re-configures the environment, module settings, and user permissions.
CommentRSSUnitTest::testCommentRSS in modules/comment/comment.test
Test comments as part of an RSS feed.
DrupalWebTestCase::drupalCreateNode in modules/simpletest/drupal_web_test_case.php
Creates a node based on default settings.
EntityCrudHookTestCase::testCommentHooks in modules/simpletest/tests/entity_crud_hook_test.test
Test hook invocations for CRUD operations on comments.
EntityCrudHookTestCase::testNodeHooks in modules/simpletest/tests/entity_crud_hook_test.test
Test hook invocations for CRUD operations on nodes.
NodeCreationTestCase::testFailedPageCreation in modules/node/node.test
Create a page node and verify that a transaction rolls back the failed creation
NodeRevisionsTestCase::testNodeRevisionWithoutLogMessage in modules/node/node.test
Checks that revisions are correctly saved without log messages.
NodeSaveTestCase::testDeterminingChanges in modules/node/node.test
Tests determing changes in hook_node_presave() and verifies the static node load cache is cleared upon save.
NodeSaveTestCase::testImport in modules/node/node.test
Import test, to check if custom node ids are saved properly. Workflow:
NodeSaveTestCase::testTimestamps in modules/node/node.test
Check that the "created" and "changed" timestamps are set correctly when saving a new node or updating an existing node.
node_form_submit in modules/node/node.pages.inc
node_revision_revert_confirm_submit in modules/node/node.pages.inc
node_save_action in modules/node/node.module
Saves a node.
PollCreateTestCase::testPollCreate in modules/poll/poll.test
SearchCommentCountToggleTestCase::testSearchCommentCountToggle in modules/search/search.test
Verify that comment count display toggles properly on comment status of node
SearchCommentTestCase::testSearchResultsComment in modules/search/search.test
Verify that comments are rendered using proper format in search results.
TaxonomyTermIndexTestCase::testTaxonomyIndex in modules/taxonomy/taxonomy.test
Tests that the taxonomy index is maintained properly.
_node_mass_update_helper in modules/node/node.admin.inc
Node Mass Update - helper function.

File

modules/node/node.module, line 1031
The core that allows content to be submitted to the site. Modules and scripts may programmatically submit nodes using the usual form API pattern.

Code

<?php
function node_save($node) {
  $transaction = db_transaction();

  try {
    // Load the stored entity, if any.
    if (!empty($node->nid) && !isset($node->original)) {
      $node->original = entity_load_unchanged('node', $node->nid);
    }

    field_attach_presave('node', $node);
    global $user;

    // Determine if we will be inserting a new node.
    if (!isset($node->is_new)) {
      $node->is_new = empty($node->nid);
    }

    // Set the timestamp fields.
    if (empty($node->created)) {
      $node->created = REQUEST_TIME;
    }
    // The changed timestamp is always updated for bookkeeping purposes,
    // for example: revisions, searching, etc.
    $node->changed = REQUEST_TIME;

    $node->timestamp = REQUEST_TIME;
    $update_node = TRUE;

    // Let modules modify the node before it is saved to the database.
    module_invoke_all('node_presave', $node);
    module_invoke_all('entity_presave', $node, 'node');

    if ($node->is_new || !empty($node->revision)) {
      // When inserting either a new node or a new node revision, $node->log
      // must be set because {node_revision}.log is a text column and therefore
      // cannot have a default value. However, it might not be set at this
      // point (for example, if the user submitting a node form does not have
      // permission to create revisions), so we ensure that it is at least an
      // empty string in that case.
      // @todo: Make the {node_revision}.log column nullable so that we can
      // remove this check.
      if (!isset($node->log)) {
        $node->log = '';
      }
    }
    elseif (!isset($node->log) || $node->log === '') {
      // If we are updating an existing node without adding a new revision, we
      // need to make sure $node->log is unset whenever it is empty. As long as
      // $node->log is unset, drupal_write_record() will not attempt to update
      // the existing database column when re-saving the revision; therefore,
      // this code allows us to avoid clobbering an existing log entry with an
      // empty one.
      unset($node->log);
    }

    // When saving a new node revision, unset any existing $node->vid so as to
    // ensure that a new revision will actually be created, then store the old
    // revision ID in a separate property for use by node hook implementations.
    if (!$node->is_new && !empty($node->revision) && $node->vid) {
      $node->old_vid = $node->vid;
      unset($node->vid);
    }

    // Save the node and node revision.
    if ($node->is_new) {
      // For new nodes, save new records for both the node itself and the node
      // revision.
      drupal_write_record('node', $node);
      _node_save_revision($node, $user->uid);
      $op = 'insert';
    }
    else {
      // For existing nodes, update the node record which matches the value of
      // $node->nid.
      drupal_write_record('node', $node, 'nid');
      // Then, if a new node revision was requested, save a new record for
      // that; otherwise, update the node revision record which matches the
      // value of $node->vid.
      if (!empty($node->revision)) {
        _node_save_revision($node, $user->uid);
      }
      else {
        _node_save_revision($node, $user->uid, 'vid');
        $update_node = FALSE;
      }
      $op = 'update';
    }
    if ($update_node) {
      db_update('node')
        ->fields(array('vid' => $node->vid))
        ->condition('nid', $node->nid)
        ->execute();
    }

    // Call the node specific callback (if any). This can be
    // node_invoke($node, 'insert') or
    // node_invoke($node, 'update').
    node_invoke($node, $op);

    // Save fields.
    $function = "field_attach_$op";
    $function('node', $node);

    module_invoke_all('node_' . $op, $node);
    module_invoke_all('entity_' . $op, $node, 'node');

    // Update the node access table for this node. There's no need to delete
    // existing records if the node is new.
    $delete = $op == 'update';
    node_access_acquire_grants($node, $delete);

    // Clear internal properties.
    unset($node->is_new);
    unset($node->original);
    // Clear the static loading cache.
    entity_get_controller('node')->resetCache(array($node->nid));

    // Ignore slave server temporarily to give time for the
    // saved node to be propagated to the slave.
    db_ignore_slave();
  }
  catch (Exception $e) {
    $transaction->rollback();
    watchdog_exception('node', $e);
    throw $e;
  }
}
?>

Comments

How to change field values

Is node_save able to save field data?

That is:

$node = node_load($nid);
$node->field_fieldname[$node->language][0]['value'] = 'new data';
node_save($node);

This doesn't work? I tried it but the field value remains. How to change the field data?

I got something to work, you

I got something to work, you may have to modify this if you have multiple languages, but I think the Languages array have string values 'und' (universal or default?).

$node = node_load($nodeID);
$node->field_fieldname['und'][0]['value'] = $val;
node_save($node);

if you are running this outside of the drupal files of course before you do that make sure to include Drupal bootstrap.inc
phase = array("DRUPAL_BOOTSTRAP_DATABASE");

LANGUAGE_NONE

The value 'und' comes from constant LANGUAGE_NONE. I'd recommend this if you don't care about languages:

$node = node_load($nodeID);
$node->field_fieldname[LANGUAGE_NONE][0]['value'] = $val;
node_save($node);

It seems node_save is really

It seems node_save is really slow for large files. Does it actually read the files when doing this programmatically in a bootstrap? I can't seem to track down why this is.

How to update field values for a given entity.

Have a look at field_attach_update().

Basically you can do this:

<?php
$node
= node_load($nid);
// A variable for easy access.
$value = &$node->logo_image[$node->language]; // or you can use field_get_items('node', $node, 'logo_image') but you have to reassign it.
// Do the desired modifications to the value(s).
if (!isset($value['title'])) {
 
$value['title'] = t('This is the logo of Company X.');
}
// Don't forget to invoke 'field_attach_presave' hooks for modules that are interested.
field_attach_presave('node', $node);
// And the actual field change for the given node (e.g. entity).
field_attach_update('node', $node);
?>

IMHO, field_attach_update() looks like an expensive function (including the preparations for it) so I would not call it frequently.

Hope this helps.

PS: I don't think node_save() updates any fields at any point - only the entity (node properties like revision id, status, etc.).

Yes, node_save() can update fields

Actually, node_save() does saves fields, here's how I'm using it :

<?php
$node
= node_load($nid);
// Set a new value to the custom field
$node->field_whatever['und'][$node->language]['value'] = 'Some random value';
// Prepare the node for saving
if ($node = node_submit($node)) {
 
// Save it
 
node_save($node);
}
?>

I don't know which solution is the best. pivano, yous said you don't often use field_attach_update(), what are you using instead ?

node_submit not applicable

The function node_submit performs the followingL

"Prepare node for saving by populating author and creation date"
(source: http://api.drupal.org/api/drupal/modules--node--node.module/function/nod...).

There is no need to run an existing node that you have modified through node_submit before node_save.

node_save then redirect

If I use drupal_goto immediately after node_save to redirect to the new node, I get "404 page not found". I suppose node_save just takes a while to save the node.

How can I stall the redirect until the node is saved?

RE: node_save then redirect

Hi,

You can use the saved object to do that. Something like this:

node_save($new_node);
drupal_goto('node/' . $new_node->nid);

Hope it helps.

Return

Probably functions like this should return a value. For example, TRUE on success, FALSE otherwise. Or resulting node object.

Plus 1

Was just looking the documentation for that exactly...

The $node object passed in

The $node object passed in should be an object. Objects are implicitly passed by reference in PHP. Therefore, after node_save is run, $node is populated with all the stuff that was done to it. No need for a return value. This stumpted me at first too, until I did a quick run through with a debugger.

Use NID

We can be sure that the node_save() was successful by checking the 'nid' property of the $node object.

<?php
 
// Assign properties, etc.
  // Save node.
 
node_save($node);
   
 
// node_save() does not return a value. It instead populates the $node object. Thus to check if the save was successful, we check the nid.
 
$node_id = $node->nid;

  return
$node_id;
?>

A custom node with an image field using node_save()

Suppose you created a custom node type called 'node_example'. It contains an image field called 'node_example_image' with 'cardinality' set to 5 (can upload 5 images). To create a node of type 'node_example' and upload 5 images (the images are taken from your custom module directory; image1.jpg, image2.jpg, ...), you can do something along the lines of:

<?php
 
// Create a node object, and add node properties.
 
$newNode = (object) NULL;
 
$newNode->type = 'node_example';
 
$newNode->uid = 0;
 
$newNode->created = strtotime("now");
 
$newNode->changed = strtotime("now");
 
$newNode->status = 1;
 
$newNode->comment = 0;
 
$newNode->promote = 0;
 
$newNode->moderate = 0;
 
$newNode->sticky = 0;
 
$newNode->language = 'und';

 
node_object_prepare($newNode);

  for (
$i = 0; $i < 5; $i++) {
   
$j = $i + 1;
   
$file_path = drupal_get_path('module', 'node_example') . '/image' . $j . '.jpg';
   
$file = (object)array(
     
"uid" => 1,
     
"uri" => $file_path,
     
"filemime" => file_get_mimetype($file_path),
     
"status" => 1
   
);

   
$file = file_copy($file, 'public://');
   
$newNode->node_example_image['und'][$i] = (array)$file;
  }

 
// Save the node.
  // The node will also get published, if $newNode->status was set to 1.
 
node_save($newNode);
?>

hook_node_insert but 404/Not Found

I need to notify Facebook when a new node is submitted, Facebook checks the response of the url, but doing it in the "insert" hook I always get a 404. I am checking it with

print_r(get_headers('url_to_page/node/' . $node->nid));
exit();

The node gets saved, but at this point, I always get a 404 Response...

It is probably the same problem as http://api.drupal.org/api/drupal/modules--node--node.module/function/nod... above. But node_save is called much earlier cannot be the solution. When I call node_save again there is an error because of a double unique identifier..

Login or register to post comments