Newer
Older
// $Id$
* The core that allows content to be submitted to the site. Modules and
* scripts may programmatically submit nodes using the usual form API pattern.
Dries Buytaert
committed
/**
* Node is not published.
*/
define('NODE_NOT_PUBLISHED', 0);
/**
* Node is published.
*/
define('NODE_PUBLISHED', 1);
/**
* Node is not promoted to front page.
*/
define('NODE_NOT_PROMOTED', 0);
/**
* Node is promoted to front page.
*/
define('NODE_PROMOTED', 1);
/**
* Node is not sticky at top of the page.
*/
define('NODE_NOT_STICKY', 0);
/**
* Node is sticky at top of the page.
*/
define('NODE_STICKY', 1);
/**
* Nodes changed before this time are always marked as read.
*
* Nodes changed after this time may be marked new, updated, or read, depending
* on their state for the current user. Defaults to 30 days ago.
*/
Dries Buytaert
committed
define('NODE_NEW_LIMIT', REQUEST_TIME - 30 * 24 * 60 * 60);
Kjartan Mannes
committed
Dries Buytaert
committed
/**
* Modules should return this value from hook_node_access() to allow access to a node.
*/
define('NODE_ACCESS_ALLOW', 'allow');
/**
* Modules should return this value from hook_node_access() to deny access to a node.
*/
define('NODE_ACCESS_DENY', 'deny');
/**
* Modules should return this value from hook_node_access() to not affect node access.
*/
define('NODE_ACCESS_IGNORE', NULL);
Dries Buytaert
committed
* Implement hook_help().
Gábor Hojtsy
committed
function node_help($path, $arg) {
// Remind site administrators about the {node_access} table being flagged
// for rebuild. We don't need to issue the message on the confirm form, or
// while the rebuild is being processed.
if ($path != 'admin/reports/status/rebuild' && $path != 'batch' && strpos($path, '#') === FALSE
&& user_access('access administration pages') && node_access_needs_rebuild()) {
if ($path == 'admin/reports/status') {
$message = t('The content access permissions need to be rebuilt.');
}
else {
$message = t('The content access permissions need to be rebuilt. Please visit <a href="@node_access_rebuild">this page</a>.', array('@node_access_rebuild' => url('admin/reports/status/rebuild')));
}
drupal_set_message($message, 'error');
}
Gábor Hojtsy
committed
switch ($path) {
$output = '<p>' . t('The node module manages content on your site, and stores all posts (regardless of type) as a "node" . In addition to basic publishing settings, including whether the post has been published, promoted to the site front page, or should remain present (or sticky) at the top of lists, the node module also records basic information about the author of a post. Optional revision control over edits is available. For additional functionality, the node module is often extended by other modules.') . '</p>';
Dries Buytaert
committed
$output .= '<p>' . t('Though each post on your site is a node, each post is also of a particular <a href="@content-type">content type</a>. <a href="@content-type">Content types</a> are used to define the characteristics of a post, including the title and description of the fields displayed on its add and edit pages. Each content type may have different default settings for <em>Publishing options</em> and other workflow controls. By default, the two content types in a standard Drupal installation are <em>Page</em> and <em>Story</em>. Use the <a href="@content-type">content types page</a> to add new or edit existing content types. Additional content types also become available as you enable additional core, contributed and custom modules.', array('@content-type' => url('admin/structure/types'))) . '</p>';
Dries Buytaert
committed
$output .= '<p>' . t('The administrative <a href="@content">content page</a> allows you to review and manage your site content. The node module makes a number of permissions available for each content type, which may be set by role on the <a href="@permissions">permissions page</a>.', array('@content' => url('admin/content'), '@permissions' => url('admin/config/people/permissions'))) . '</p>';
$output .= '<p>' . t('For more information, see the online handbook entry for <a href="@node">Node module</a>.', array('@node' => 'http://drupal.org/handbook/modules/node/')) . '</p>';
Angie Byron
committed
Dries Buytaert
committed
case 'admin/content':
Gábor Hojtsy
committed
return ' '; // Return a non-null value so that the 'more help' link is shown.
Angie Byron
committed
Dries Buytaert
committed
case 'admin/structure/types/add':
Angie Byron
committed
return '<p>' . t('Each piece of content is of a specific content type. Each <em>content type</em> can have different fields, behaviors, and permissions assigned to it.') . '</p>';
Angie Byron
committed
Dries Buytaert
committed
case 'admin/structure/types/manage/' . $arg[3] . '/fields':
Angie Byron
committed
return '<p>' . t('This form lets you add, edit, and arrange fields within the %type content type.', array('%type' => node_type_get_name($arg[3]))) . '</p>';
Dries Buytaert
committed
case 'admin/structure/types/manage/' . $arg[3] . '/display':
Angie Byron
committed
return '<p>' . t('This form lets you configure how fields and labels are displayed when %type content is viewed in teaser and full-page mode.', array('%type' => node_type_get_name($arg[3]))) . '</p>';
Dries Buytaert
committed
case 'admin/structure/types/manage/' . $arg[3] . '/display/' . $arg[5]:
Angie Byron
committed
return '<p>' . t('This form lets you configure how fields should be displayed when rendered %type content in the following contexts.', array('%type' => node_type_get_name($arg[3]))) . '</p>';
Gábor Hojtsy
committed
case 'node/%/revisions':
return '<p>' . t('The revisions let you track differences between multiple versions of a post.') . '</p>';
Angie Byron
committed
Gábor Hojtsy
committed
case 'node/%/edit':
$node = node_load($arg[1]);
Angie Byron
committed
$type = node_type_get_type($node);
return (!empty($type->help) ? '<p>' . filter_xss_admin($type->help) . '</p>' : '');
Gábor Hojtsy
committed
if ($arg[0] == 'node' && $arg[1] == 'add' && $arg[2]) {
Angie Byron
committed
$type = node_type_get_type(str_replace('-', '_', $arg[2]));
return (!empty($type->help) ? '<p>' . filter_xss_admin($type->help) . '</p>' : '');
Dries Buytaert
committed
}
Dries Buytaert
committed
/**
Dries Buytaert
committed
* Implement hook_theme().
Dries Buytaert
committed
*/
function node_theme() {
return array(
Dries Buytaert
committed
'node' => array(
'arguments' => array('elements' => NULL),
'template' => 'node',
Dries Buytaert
committed
),
Dries Buytaert
committed
'node_list' => array(
'arguments' => array('items' => NULL, 'title' => NULL),
),
'node_search_admin' => array(
'arguments' => array('form' => NULL),
),
'node_filter_form' => array(
'arguments' => array('form' => NULL),
'file' => 'node.admin.inc',
Dries Buytaert
committed
),
'node_filters' => array(
'arguments' => array('form' => NULL),
'file' => 'node.admin.inc',
Dries Buytaert
committed
),
'node_add_list' => array(
'arguments' => array('content' => NULL),
'file' => 'node.pages.inc',
Dries Buytaert
committed
),
'node_form' => array(
'arguments' => array('form' => NULL),
'file' => 'node.pages.inc',
Dries Buytaert
committed
),
'node_preview' => array(
'arguments' => array('node' => NULL),
'file' => 'node.pages.inc',
Dries Buytaert
committed
),
'node_log_message' => array(
'arguments' => array('log' => NULL),
),
Dries Buytaert
committed
'node_admin_overview' => array(
'arguments' => array('name' => NULL, 'type' => NULL),
),
Dries Buytaert
committed
);
}
Dries Buytaert
committed
* Implement hook_cron().
Kjartan Mannes
committed
function node_cron() {
Dries Buytaert
committed
db_delete('history')
->condition('timestamp', NODE_NEW_LIMIT, '<')
->execute();
Kjartan Mannes
committed
}
Dries Buytaert
committed
* Implement hook_entity_info().
Dries Buytaert
committed
function node_entity_info() {
'label' => t('Node'),
Dries Buytaert
committed
'controller class' => 'NodeController',
'base table' => 'node',
'revision table' => 'node_revision',
'fieldable' => TRUE,
'object keys' => array(
'id' => 'nid',
'revision' => 'vid',
'bundle' => 'type',
),
Angie Byron
committed
'bundle keys' => array(
'bundle' => 'type',
),
'bundles' => array(),
// Bundles must provide a human readable name so we can create help and error
// messages, and the path to attach Field admin pages to.
foreach (node_type_get_names() as $type => $name) {
$return['node']['bundles'][$type] = array(
'label' => $name,
'admin' => array(
Angie Byron
committed
'path' => 'admin/structure/types/manage/%node_type',
'real path' => 'admin/structure/types/manage/' . str_replace('_', '-', $type),
'bundle argument' => 4,
'access arguments' => array('administer content types'),
),
);
}
Dries Buytaert
committed
* Implement hook_field_build_modes().
*/
function node_field_build_modes($obj_type) {
$modes = array();
if ($obj_type == 'node') {
$modes = array(
'teaser' => t('Teaser'),
'full' => t('Full node'),
'rss' => t('RSS'),
// Search integration is provided by node.module, so search-related
// build-modes for nodes are defined here and not in search.module.
'search_index' => t('Search Index'),
'search_result' => t('Search Result'),
/**
* Gather a listing of links to nodes.
*
* @param $result
Dries Buytaert
committed
* A DB result object from a query to fetch node entities. If your query
Dries Buytaert
committed
* joins the <code>node_comment_statistics</code> table so that the
* <code>comment_count</code> field is available, a title attribute will
* be added to show the number of comments.
* @param $title
* A heading for the resulting list.
*
* @return
Dries Buytaert
committed
* An HTML list suitable as content for a block, or FALSE if no result can
* fetch from DB result object.
Dries Buytaert
committed
$items = array();
Dries Buytaert
committed
$num_rows = FALSE;
Dries Buytaert
committed
foreach ($result as $node) {
$items[] = l($node->title, 'node/' . $node->nid, !empty($node->comment_count) ? array('attributes' => array('title' => format_plural($node->comment_count, '1 comment', '@count comments'))) : array());
Dries Buytaert
committed
$num_rows = TRUE;
Dries Buytaert
committed
return $num_rows ? theme('node_list', array('items' => $items, 'title' => $title)) : FALSE;
Gábor Hojtsy
committed
*
* @ingroup themeable
Dries Buytaert
committed
function theme_node_list($variables) {
return theme('item_list', $variables);
/**
* Update the 'last viewed' timestamp of the specified node for current user.
*/
function node_tag_new($nid) {
global $user;
if ($user->uid) {
Dries Buytaert
committed
db_merge('history')
->key(array(
'uid' => $user->uid,
'nid' => $nid,
))
->fields(array('timestamp' => REQUEST_TIME))
->execute();
/**
* Retrieves the timestamp at which the current user last viewed the
* specified node.
*/
Dries Buytaert
committed
$history[$nid] = db_query("SELECT timestamp FROM {history} WHERE uid = :uid AND nid = :nid", array(':uid' => $user->uid, ':nid' => $nid))->fetchObject();
return (isset($history[$nid]->timestamp) ? $history[$nid]->timestamp : 0);
Dries Buytaert
committed
* Decide on the type of marker to be displayed for a given node.
* @param $nid
* Node ID whose history supplies the "last viewed" timestamp.
* @param $timestamp
* Time which is compared against node's "last viewed" timestamp.
Dries Buytaert
committed
* @return
* One of the MARK constants.
Dries Buytaert
committed
function node_mark($nid, $timestamp) {
Dries Buytaert
committed
if (!$user->uid) {
return MARK_READ;
}
Dries Buytaert
committed
$cache[$nid] = node_last_viewed($nid);
Dries Buytaert
committed
if ($cache[$nid] == 0 && $timestamp > NODE_NEW_LIMIT) {
return MARK_NEW;
}
elseif ($timestamp > $cache[$nid] && $timestamp > NODE_NEW_LIMIT) {
return MARK_UPDATED;
}
return MARK_READ;
Neil Drumm
committed
/**
Angie Byron
committed
* Extract the type name.
Neil Drumm
committed
*
* @param $node
Angie Byron
committed
* Either a string or object, containing the node type information.
Neil Drumm
committed
*
* @return
Angie Byron
committed
* Node type of the passed in data.
Neil Drumm
committed
*/
Angie Byron
committed
function _node_extract_type($node) {
return is_object($node) ? $node->type : $node;
}
Angie Byron
committed
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
/**
* Returns a list of all the available node types.
*
* @return
* An array of node types, keyed by the type.
* @see node_type_get_type()
*/
function node_type_get_types() {
return _node_types_build()->types;
}
/**
* Returns the node type of the passed node or node type string.
*
*@param $node
* A node object or string that indicates the node type to return.
* @return
* A single node type, as an object or FALSE if the node type is not found.
* The node type is an array with following content:
*
* @code
* array(
* 'type' => 'Machine readable type name',
* 'name' => 'Name of the node type',
* 'base' => 'Indicates to which module this node type belongs',
* 'description' => 'Description of the node type',
* // ...
* )
* @endcode
*/
function node_type_get_type($node) {
$type = _node_extract_type($node);
$types = _node_types_build()->types;
return isset($types[$type]) ? $types[$type] : FALSE;
}
/**
* Returns the node type base of the passed node or node type string.
*
* The base indicates which module implement this node type and is used to
* execute node type specific hooks.
*
* @see node_invoke()
*
* @param $node
* A node object or string that indicates the node type to return.
* @return
* The node type base or FALSE if the node type is not found.
*/
function node_type_get_base($node) {
$type = _node_extract_type($node);
$types = _node_types_build()->types;
return isset($types[$type]) && isset($types[$type]->base) ? $types[$type]->base : FALSE;
}
/**
* Returns a list of available node names.
*
* @return
* An array of node type names, keyed by the type.
*/
function node_type_get_names() {
return _node_types_build()->names;
}
/**
* Returns the node type name of the passed node or node type string.
*
* @param $node
* A node object or string that indicates the node type to return.
*
* @return
* The node type name or FALSE if the node type is not found.
*/
function node_type_get_name($node) {
$type = _node_extract_type($node);
$types = _node_types_build()->names;
return isset($types[$type]) ? $types[$type] : FALSE;
Neil Drumm
committed
}
/**
Angie Byron
committed
* Resets the database cache of node types.
*
* All new or non-modified module-defined node types are saved to the database.
Neil Drumm
committed
*/
function node_types_rebuild() {
Angie Byron
committed
// Reset and load updated node types.
Angie Byron
committed
drupal_static_reset('_node_types_build');
Angie Byron
committed
foreach (node_type_get_types() as $type => $info) {
Neil Drumm
committed
if (!empty($info->is_new)) {
node_type_save($info);
}
Dries Buytaert
committed
if (!empty($info->disabled)) {
node_type_delete($info->type);
}
}
}
Angie Byron
committed
/**
* Menu argument loader; Load a node type by string.
*
* @param $name
* The machine-readable name of a node type to load; having '_' replaced with
* '-'.
*
* @return
* A node type object or FALSE if $name does not exist.
*/
function node_type_load($name) {
return node_type_get_type(strtr($name, array('-' => '_')));
}
Neil Drumm
committed
* Saves a node type to the database.
*
* @param $info
* The node type to save, as an object.
Neil Drumm
committed
* Status flag indicating outcome of the operation.
Neil Drumm
committed
function node_type_save($info) {
$is_existing = FALSE;
$existing_type = !empty($info->old_type) ? $info->old_type : $info->type;
Angie Byron
committed
$is_existing = (bool) db_query_range('SELECT 1 FROM {node_type} WHERE type = :type', 0, 1, array(':type' => $existing_type))->fetchField();
$type = node_type_set_defaults($info);
$fields = array(
'type' => (string) $type->type,
'name' => (string) $type->name,
'base' => (string) $type->base,
'has_title' => (int) $type->has_title,
'title_label' => (string) $type->title_label,
'has_body' => (int) $type->has_body,
'body_label' => (string) $type->body_label,
'description' => (string) $type->description,
'help' => (string) $type->help,
'custom' => (int) $type->custom,
'modified' => (int) $type->modified,
'locked' => (int) $type->locked,
);
Neil Drumm
committed
if ($is_existing) {
Dries Buytaert
committed
db_update('node_type')
->fields($fields)
->condition('type', $existing_type)
->execute();
Neil Drumm
committed
Dries Buytaert
committed
field_attach_rename_bundle('node', $type->old_type, $type->type);
Dries Buytaert
committed
node_configure_fields($type);
module_invoke_all('node_type_update', $type);
Angie Byron
committed
$status = SAVED_UPDATED;
Neil Drumm
committed
}
else {
$fields['orig_type'] = (string) $type->orig_type;
Dries Buytaert
committed
db_insert('node_type')
->fields($fields)
->execute();
Neil Drumm
committed
Dries Buytaert
committed
field_attach_create_bundle('node', $type->type);
Dries Buytaert
committed
node_configure_fields($type);
module_invoke_all('node_type_insert', $type);
Angie Byron
committed
$status = SAVED_NEW;
Neil Drumm
committed
}
Angie Byron
committed
// Clear the node type cache.
drupal_static_reset('_node_types_build');
return $status;
}
Dries Buytaert
committed
Dries Buytaert
committed
/**
* Manage the field(s) for a node type.
*
* Currently, the node module manages a single Field API field,
* 'body'. If $type->has_body is true, this function ensures the
* 'body' field exists and creates an instance of it for the bundle
* $type->type (e.g. 'page', 'story', ...). If $type->has_body is
* false, this function removes the instance (if it exists) for the
* 'body' field on $type->type.
*/
function node_configure_fields($type) {
// Add or remove the body field, as needed.
$field = field_info_field('body');
Dries Buytaert
committed
$instance = field_info_instance('node', 'body', $type->type);
Dries Buytaert
committed
if ($type->has_body) {
if (empty($field)) {
$field = array(
'field_name' => 'body',
'type' => 'text_with_summary',
);
$field = field_create_field($field);
}
if (empty($instance)) {
$instance = array(
'field_name' => 'body',
Dries Buytaert
committed
'object_type' => 'node',
Dries Buytaert
committed
'bundle' => $type->type,
'label' => $type->body_label,
'widget_type' => 'text_textarea_with_summary',
'settings' => array('display_summary' => TRUE),
// Define default formatters for the teaser and full view.
Dries Buytaert
committed
'display' => array(
'full' => array(
'label' => 'hidden',
'type' => 'text_default',
Dries Buytaert
committed
),
Dries Buytaert
committed
'teaser' => array(
'label' => 'hidden',
'type' => 'text_summary_or_trimmed',
),
Dries Buytaert
committed
),
);
Dries Buytaert
committed
field_create_instance($instance);
}
else {
$instance['label'] = $type->body_label;
$instance['settings']['display_summary'] = TRUE;
field_update_instance($instance);
}
}
elseif (!empty($instance)) {
field_delete_instance($instance);
}
if ($type->has_title) {
// Add the title field if not present.
$field = field_info_field('title');
Dries Buytaert
committed
$instance = field_info_instance('node', 'title', $type->type);
if (empty($field)) {
$field = array(
'field_name' => 'title',
'type' => 'text',
);
$field = field_create_field($field);
}
if (empty($instance)) {
$weight = -5;
$instance = array(
'field_name' => 'title',
Dries Buytaert
committed
'object_type' => 'node',
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
'bundle' => $type->type,
'label' => $type->title_label,
'widget_type' => 'text',
'widget' => array(
'weight' => $weight,
),
'required' => TRUE,
'locked' => TRUE,
'display' => array(
'full' => array(
'label' => 'hidden',
'type' => 'text_default',
'weight' => $weight,
),
'teaser' => array(
'label' => 'hidden',
'type' => 'text_default',
'weight' => $weight,
),
),
);
field_create_instance($instance);
}
else {
$instance['label'] = $type->title_label;
field_update_instance($instance);
}
}
Dries Buytaert
committed
}
/**
* Deletes a node type from the database.
*
* @param $type
* The machine-readable name of the node type to be deleted.
*/
function node_type_delete($type) {
Angie Byron
committed
$info = node_type_get_type($type);
Dries Buytaert
committed
db_delete('node_type')
->condition('type', $type)
->execute();
module_invoke_all('node_type_delete', $info);
Angie Byron
committed
// Clear the node type cache.
drupal_static_reset('_node_types_build');
}
/**
Neil Drumm
committed
* Updates all nodes of one type to be of another type.
*
Neil Drumm
committed
* The current node type of the nodes.
* @param $type
* The new node type of the nodes.
*
* @return
Neil Drumm
committed
* The number of nodes whose node type field was modified.
*/
Neil Drumm
committed
function node_type_update_nodes($old_type, $type) {
return db_update('node')
Dries Buytaert
committed
->fields(array('type' => $type))
->condition('type', $old_type)
->execute();
Dries Buytaert
committed
* Builds and returns the list of available node types.
*
* The list of types is built by querying hook_node_info() in all modules, and
* by comparing this information with the node types in the {node_type} table.
Neil Drumm
committed
function _node_types_build() {
$_node_types = &drupal_static(__FUNCTION__);
Angie Byron
committed
if (is_object($_node_types)) {
return $_node_types;
}
Dries Buytaert
committed
$_node_types = (object)array('types' => array(), 'names' => array());
Neil Drumm
committed
$info_array = module_invoke_all('node_info');
foreach ($info_array as $type => $info) {
$info['type'] = $type;
Angie Byron
committed
$_node_types->types[$type] = node_type_set_defaults($info);
$_node_types->names[$type] = $info['name'];
Neil Drumm
committed
}
Dries Buytaert
committed
$type_result = db_select('node_type', 'nt')
->fields('nt')
->orderBy('nt.type', 'ASC')
->addTag('node_type_access')
->execute();
foreach ($type_result as $type_object) {
Dries Buytaert
committed
// Check for node types from disabled modules and mark their types for removal.
// Types defined by the node module in the database (rather than by a separate
Angie Byron
committed
// module using hook_node_info) have a base value of 'node_content'. The isset()
// check prevents errors on old (pre-Drupal 7) databases.
if (isset($type_object->base) && $type_object->base != 'node_content' && empty($info_array[$type_object->type])) {
Gábor Hojtsy
committed
$type_object->disabled = TRUE;
Dries Buytaert
committed
}
Angie Byron
committed
if (!isset($_node_types->types[$type_object->type]) || $type_object->modified) {
$_node_types->types[$type_object->type] = $type_object;
$_node_types->names[$type_object->type] = $type_object->name;
Neil Drumm
committed
if ($type_object->type != $type_object->orig_type) {
Angie Byron
committed
unset($_node_types->types[$type_object->orig_type]);
unset($_node_types->names[$type_object->orig_type]);
Neil Drumm
committed
}
}
}
Angie Byron
committed
asort($_node_types->names);
Neil Drumm
committed
Angie Byron
committed
return $_node_types;
Neil Drumm
committed
}
/**
* Set the default values for a node type.
*
* The defaults are for a type defined through hook_node_info().
* When populating a custom node type $info should have the 'custom'
* key set to 1.
*
* @param $info
* An object or array containing values to override the defaults.
*
* @return
* A node type object.
Neil Drumm
committed
*/
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
function node_type_set_defaults($info = array()) {
static $type;
if (!isset($type)) {
$type = new stdClass();
$type->type = '';
$type->name = '';
$type->base = '';
$type->description = '';
$type->help = '';
$type->has_title = 1;
$type->has_body = 1;
$type->title_label = t('Title');
$type->body_label = t('Body');
$type->custom = 0;
$type->modified = 0;
$type->locked = 1;
$type->is_new = 1;
}
$new_type = clone $type;
$info = (array) $info;
foreach ($info as $key => $data) {
$new_type->$key = $data;
}
// If the type has no title or body, set an empty label.
if (!$new_type->has_title) {
$new_type->title_label = '';
}
if (!$new_type->has_body) {
$new_type->body_label = '';
}
$new_type->orig_type = isset($info['type']) ? $info['type'] : '';
return $new_type;
Dries Buytaert
committed
* A node object or a string containing the node type.
* @param $hook
* A string containing the name of the hook.
* @return
* TRUE if the $hook exists in the node type of $node.
function node_hook($node, $hook) {
Angie Byron
committed
$base = node_type_get_base($node);
return module_hook($base, $hook);
Dries Buytaert
committed
* A node object or a string containing the node type.
* @param $hook
* A string containing the name of the hook.
* @param $a2, $a3, $a4
* Arguments to pass on to the hook, after the $node argument.
* @return
function node_invoke($node, $hook, $a2 = NULL, $a3 = NULL, $a4 = NULL) {
if (node_hook($node, $hook)) {
Angie Byron
committed
$base = node_type_get_base($node);
$function = $base . '_' . $hook;
Dries Buytaert
committed
* Load node entities from the database.
*
* This function should be used whenever you need to load more than one node
* from the database. Nodes are loaded into memory and will not require
* database access if loaded again during the same page request.
Dries Buytaert
committed
* @see entity_load()
*
* @param $nids
* An array of node IDs.
* @param $conditions
* An array of conditions on the {node} table in the form 'field' => $value.
* An array of node objects indexed by nid.
function node_load_multiple($nids = array(), $conditions = array(), $reset = FALSE) {
Dries Buytaert
committed
return entity_load('node', $nids, $conditions, $reset);
}
/**
* Load a node object from the database.
*
* @param $nid
* The node ID.
* @param $vid
* The revision ID.
* @param $reset
Angie Byron
committed
* Whether to reset the node_load_multiple cache.
*
* @return
* A fully-populated node object.
*/
Dries Buytaert
committed
function node_load($nid = NULL, $vid = NULL, $reset = FALSE) {
$nids = (isset($nid) ? array($nid) : array());
$conditions = (isset($vid) ? array('vid' => $vid) : array());
$node = node_load_multiple($nids, $conditions, $reset);
return $node ? reset($node) : FALSE;
/**
* Perform validation checks on the given node.
*/
function node_validate($node, $form = array()) {
Angie Byron
committed
$type = node_type_get_type($node);
if (isset($node->nid) && (node_last_changed($node->nid) > $node->changed)) {
Dries Buytaert
committed
form_set_error('changed', t('The content on this page has either been modified by another user, or you have already submitted modifications using this form. As a result, your changes cannot be saved.'));
}
if (user_access('administer nodes')) {
// Validate the "authored by" field.
Angie Byron
committed
if (!empty($node->name) && !($account = user_load_by_name($node->name))) {
// The use of empty() is mandatory in the context of usernames
// as the empty string denotes the anonymous user. In case we
// are dealing with an anonymous user we set the user ID to 0.
form_set_error('name', t('The username %name does not exist.', array('%name' => $node->name)));
}
// Validate the "authored on" field.
if (!empty($node->date) && strtotime($node->date) === FALSE) {
form_set_error('date', t('You have to specify a valid date.'));
}
}
// Do node-type-specific validation checks.
node_invoke($node, 'validate', $form);
Dries Buytaert
committed
module_invoke_all('node_validate', $node, $form);
}
/**
* Prepare node for save and allow modules to make changes.
*/
function node_submit($node) {
global $user;
if (user_access('administer nodes')) {
// Populate the "authored by" field.
Angie Byron
committed
if ($account = user_load_by_name($node->name)) {
$node->uid = $account->uid;
}
else {
$node->uid = 0;
}
}
Dries Buytaert
committed
$node->created = !empty($node->date) ? strtotime($node->date) : REQUEST_TIME;
$node->validated = TRUE;
return $node;
}
Angie Byron
committed
* Save changes to a node or add a new node.
*
* @param $node
* The $node object to be saved. If $node->nid is
* omitted (or $node->is_new is TRUE), a new node will be added.
function node_save($node) {
// Let modules modify the node before it is saved to the database.
Dries Buytaert
committed
module_invoke_all('node_presave', $node);
Angie Byron
committed
if (!isset($node->is_new)) {
$node->is_new = empty($node->nid);
Angie Byron
committed
}
Angie Byron
committed
if ($node->is_new) {
$node->is_new = TRUE;
Gábor Hojtsy
committed
// When inserting a node, $node->log must be set because
Dries Buytaert
committed
// {node_revision}.log does not (and cannot) have a default
Dries Buytaert
committed
// value. If the user does not have permission to create
Gábor Hojtsy
committed
// revisions, however, the form will not contain an element for
// log so $node->log will be unset at this point.
if (!isset($node->log)) {
$node->log = '';
}
Dries Buytaert
committed
elseif (!empty($node->revision)) {
$node->old_vid = $node->vid;
Angie Byron
committed
unset($node->vid);
Dries Buytaert
committed
}
// When updating a node, avoid clobbering an existing log entry with an empty one.
Dries Buytaert
committed
if (empty($node->log)) {
unset($node->log);
// Set some required fields:
if (empty($node->created)) {
Dries Buytaert
committed
$node->created = REQUEST_TIME;
}
// The changed timestamp is always updated for bookkeeping purposes (revisions, searching, ...)
Dries Buytaert
committed
$node->changed = REQUEST_TIME;
Dries Buytaert
committed
$node->timestamp = REQUEST_TIME;
Dries Buytaert
committed
$update_node = TRUE;
Dries Buytaert
committed
// When converting the title property to fields we preserved the {node}.title
// db column for performance, setting the default language value into this
// column. After this we restore the field data structure to the previous node
// title field.
$title_field = $node->title;
$langcode = FIELD_LANGUAGE_NONE;
$node->title = $title_field[$langcode][0]['value'];
Gábor Hojtsy
committed
// Generate the node table query and the node_revisions table query.
if ($node->is_new) {
Dries Buytaert
committed
drupal_write_record('node', $node);
_node_save_revision($node, $user->uid);
Dries Buytaert
committed
$op = 'insert';
Dries Buytaert
committed
drupal_write_record('node', $node, 'nid');
Dries Buytaert
committed
if (!empty($node->revision)) {
_node_save_revision($node, $user->uid);
_node_save_revision($node, $user->uid, 'vid');
Dries Buytaert
committed
$update_node = FALSE;
Dries Buytaert
committed
$op = 'update';
Dries Buytaert
committed
if ($update_node) {
Dries Buytaert
committed
db_update('node')
->fields(array('vid' => $node->vid))
->condition('nid', $node->nid)
->execute();
Dries Buytaert
committed
}
// Restore the title field data structure after db storage.
$node->title = $title_field;
Dries Buytaert
committed
// Call the node specific callback (if any). This can be
// node_invoke($node, 'insert') or
// node_invoke($node, 'update').
Dries Buytaert
committed
node_invoke($node, $op);
// Save fields.
$function = "field_attach_$op";
$function('node', $node);
module_invoke_all('node_' . $op, $node);
Dries Buytaert
committed
// Update the node access table for this node.
node_access_acquire_grants($node);
Angie Byron
committed
// Clear internal properties.
unset($node->is_new);
// Clear the page and block caches.
Dries Buytaert
committed
// Ignore slave server temporarily to give time for the
// saved node to be propagated to the slave.
db_ignore_slave();
/**
Gábor Hojtsy
committed
* Helper function to save a revision with the uid of the current user.
*
* Node is taken by reference, because drupal_write_record() updates the
Gábor Hojtsy
committed
* $node with the revision id, and we need to pass that back to the caller.