View source
<?php
define('NODE_NEW_LIMIT', time() - 30 * 24 * 60 * 60);
function node_help($section) {
switch ($section) {
case 'admin/help#node':
$output = '<p>' . t('All content in a website is stored and treated as <b>nodes</b>. Therefore nodes are any postings such as blogs, stories, polls and forums. The node module manages these content types and is one of the strengths of Drupal over other content management systems.') . '</p>';
$output .= '<p>' . t('Treating all content as nodes allows the flexibility of creating new types of content. It also allows you to painlessly apply new features or changes to all content. Comments are not stored as nodes but are always associated with a node.') . '</p>';
$output .= t('<p>Node module features</p>
<ul>
<li>The list tab provides an interface to search and sort all content on your site.</li>
<li>The configure settings tab has basic settings for content on your site.</li>
<li>The configure content types tab lists all content types for your site and lets you configure their default workflow.</li>
<li>The search tab lets you search all content on your site</li>
</ul>
');
$output .= t('<p>You can</p>
<ul>
<li>search for content at <a href="%search">search</a>.</li>
<li>administer nodes at <a href="%admin-settings-content-types">administer >> settings >> content types</a>.</li>
</ul>
', array(
'%search' => url('search'),
'%admin-settings-content-types' => url('admin/settings/content-types'),
));
$output .= '<p>' . t('For more information please read the configuration and customization handbook <a href="%node">Node page</a>.', array(
'%node' => 'http://drupal.org/handbook/modules/node/',
)) . '</p>';
return $output;
case 'admin/modules#description':
return t('Allows content to be submitted to the site and displayed on pages.');
case 'admin/node/configure':
case 'admin/node/configure/settings':
return t('<p>Settings for the core of Drupal. Almost everything is a node so these settings will affect most of the site.</p>');
case 'admin/node':
return t('<p>Below is a list of all of the posts on your site. Other forms of content are listed elsewhere (e.g. <a href="%comments">comments</a>).</p><p>Clicking a title views the post, while clicking an author\'s name views their user information.</p>', array(
'%comments' => url('admin/comment'),
));
case 'admin/node/search':
return t('<p>Enter a simple pattern to search for a post. This can include the wildcard character *.<br />For example, a search for "br*" might return "bread bakers", "our daily bread" and "brenda".</p>');
}
if (arg(0) == 'node' && is_numeric(arg(1)) && arg(2) == 'revisions' && !arg(3)) {
return t('The revisions let you track differences between multiple versions of a post.');
}
if (arg(0) == 'node' && arg(1) == 'add' && ($type = arg(2))) {
return filter_xss_admin(variable_get($type . '_help', ''));
}
}
function node_cron() {
db_query('DELETE FROM {history} WHERE timestamp < %d', NODE_NEW_LIMIT);
}
function node_title_list($result, $title = NULL) {
while ($node = db_fetch_object($result)) {
$items[] = l($node->title, 'node/' . $node->nid, $node->comment_count ? array(
'title' => format_plural($node->comment_count, '1 comment', '%count comments'),
) : '');
}
return theme('node_list', $items, $title);
}
function theme_node_list($items, $title = NULL) {
return theme('item_list', $items, $title);
}
function node_tag_new($nid) {
global $user;
if ($user->uid) {
if (node_last_viewed($nid)) {
db_query('UPDATE {history} SET timestamp = %d WHERE uid = %d AND nid = %d', time(), $user->uid, $nid);
}
else {
@db_query('INSERT INTO {history} (uid, nid, timestamp) VALUES (%d, %d, %d)', $user->uid, $nid, time());
}
}
}
function node_last_viewed($nid) {
global $user;
static $history;
if (!isset($history[$nid])) {
$history[$nid] = db_fetch_object(db_query("SELECT timestamp FROM {history} WHERE uid = '{$user->uid}' AND nid = %d", $nid));
}
return isset($history[$nid]->timestamp) ? $history[$nid]->timestamp : 0;
}
function node_mark($nid, $timestamp) {
global $user;
static $cache;
if (!$user->uid) {
return MARK_READ;
}
if (!isset($cache[$nid])) {
$cache[$nid] = node_last_viewed($nid);
}
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;
}
function node_teaser($body, $format = NULL) {
$size = variable_get('teaser_length', 600);
$delimiter = strpos($body, '<!--break-->');
if ($size == 0 && $delimiter === FALSE) {
return $body;
}
if ($delimiter !== FALSE) {
return substr($body, 0, $delimiter);
}
if (isset($format)) {
$filters = filter_list_format($format);
if (isset($filters['filter/1']) && strpos($body, '<?') !== FALSE) {
return $body;
}
}
if (strlen($body) < $size) {
return $body;
}
$teaser = truncate_utf8($body, $size);
$position = 0;
$reversed = strrev($teaser);
$breakpoints = array(
'</p>' => 0,
'<br />' => 6,
'<br>' => 4,
"\n" => 1,
);
foreach ($breakpoints as $point => $offset) {
$length = strpos($reversed, strrev($point));
if ($length !== FALSE) {
$position = -$length - $offset;
return $position == 0 ? $teaser : substr($teaser, 0, $position);
}
}
$breakpoints = array(
'. ' => 1,
'! ' => 1,
'? ' => 1,
'。' => 0,
'؟ ' => 1,
);
$min_length = strlen($reversed);
foreach ($breakpoints as $point => $offset) {
$length = strpos($reversed, strrev($point));
if ($length !== FALSE) {
$min_length = min($length, $min_length);
$position = 0 - $length - $offset;
}
}
return $position == 0 ? $teaser : substr($teaser, 0, $position);
}
function _node_names($op = '', $node = NULL) {
static $node_names = array();
static $node_list = array();
if (empty($node_names)) {
$node_names = module_invoke_all('node_info');
foreach ($node_names as $type => $value) {
$node_list[$type] = $value['name'];
}
}
if ($node) {
if (is_array($node)) {
$type = $node['type'];
}
elseif (is_object($node)) {
$type = $node->type;
}
elseif (is_string($node)) {
$type = $node;
}
if (!isset($node_names[$type])) {
return FALSE;
}
}
switch ($op) {
case 'base':
return $node_names[$type]['base'];
case 'list':
return $node_list;
case 'name':
return $node_list[$type];
}
}
function node_get_base($node) {
return _node_names('base', $node);
}
function node_get_name($node) {
return _node_names('name', $node);
}
function node_get_types() {
return _node_names('list');
}
function node_hook(&$node, $hook) {
return module_hook(node_get_base($node), $hook);
}
function node_invoke(&$node, $hook, $a2 = NULL, $a3 = NULL, $a4 = NULL) {
if (node_hook($node, $hook)) {
$function = node_get_base($node) . "_{$hook}";
return $function($node, $a2, $a3, $a4);
}
}
function node_invoke_nodeapi(&$node, $op, $a3 = NULL, $a4 = NULL) {
$return = array();
foreach (module_implements('nodeapi') as $name) {
$function = $name . '_nodeapi';
$result = $function($node, $op, $a3, $a4);
if (isset($result) && is_array($result)) {
$return = array_merge($return, $result);
}
else {
if (isset($result)) {
$return[] = $result;
}
}
}
return $return;
}
function node_load($param = array(), $revision = NULL, $reset = NULL) {
static $nodes = array();
if ($reset) {
$nodes = array();
}
$cachable = $revision == NULL;
$arguments = array();
if (is_numeric($param)) {
if ($cachable && isset($nodes[$param])) {
return is_object($nodes[$param]) ? drupal_clone($nodes[$param]) : $nodes[$param];
}
$cond = 'n.nid = %d';
$arguments[] = $param;
}
else {
foreach ($param as $key => $value) {
$cond[] = 'n.' . db_escape_string($key) . " = '%s'";
$arguments[] = $value;
}
$cond = implode(' AND ', $cond);
}
if ($revision) {
array_unshift($arguments, $revision);
$node = db_fetch_object(db_query('SELECT n.nid, r.vid, n.type, n.status, n.created, n.changed, n.comment, n.promote, n.moderate, n.sticky, r.timestamp AS revision_timestamp, r.title, r.body, r.teaser, r.log, r.format, u.uid, u.name, u.picture, u.data FROM {node} n INNER JOIN {users} u ON u.uid = n.uid INNER JOIN {node_revisions} r ON r.nid = n.nid AND r.vid = %d WHERE ' . $cond, $arguments));
}
else {
$node = db_fetch_object(db_query('SELECT n.nid, n.vid, n.type, n.status, n.created, n.changed, n.comment, n.promote, n.moderate, n.sticky, r.timestamp AS revision_timestamp, r.title, r.body, r.teaser, r.log, r.format, u.uid, u.name, u.picture, u.data FROM {node} n INNER JOIN {users} u ON u.uid = n.uid INNER JOIN {node_revisions} r ON r.vid = n.vid WHERE ' . $cond, $arguments));
}
if ($node->nid) {
if ($extra = node_invoke($node, 'load')) {
foreach ($extra as $key => $value) {
$node->{$key} = $value;
}
}
if ($extra = node_invoke_nodeapi($node, 'load')) {
foreach ($extra as $key => $value) {
$node->{$key} = $value;
}
}
if ($cachable) {
$nodes[$node->nid] = is_object($node) ? drupal_clone($node) : $node;
}
}
return $node;
}
function node_save(&$node) {
global $user;
$node->is_new = false;
if (empty($node->nid)) {
$node->is_new = true;
$node->nid = db_next_id('{node}_nid');
$node->vid = db_next_id('{node_revisions}_vid');
}
else {
$node_current = node_load($node->nid);
foreach ($node as $field => $data) {
$node_current->{$field} = $data;
}
$node = $node_current;
if ($node->revision) {
$node->old_vid = $node->vid;
$node->vid = db_next_id('{node_revisions}_vid');
}
}
if (empty($node->created)) {
$node->created = time();
}
$node->changed = time();
$revisions_table_values = array(
'nid' => $node->nid,
'vid' => $node->vid,
'title' => $node->title,
'body' => $node->body,
'teaser' => $node->teaser,
'log' => $node->log,
'timestamp' => $node->changed,
'uid' => $user->uid,
'format' => $node->format,
);
$revisions_table_types = array(
'nid' => '%d',
'vid' => '%d',
'title' => "'%s'",
'body' => "'%s'",
'teaser' => "'%s'",
'log' => "'%s'",
'timestamp' => '%d',
'uid' => '%d',
'format' => '%d',
);
$node_table_values = array(
'nid' => $node->nid,
'vid' => $node->vid,
'title' => $node->title,
'type' => $node->type,
'uid' => $node->uid,
'status' => $node->status,
'created' => $node->created,
'changed' => $node->changed,
'comment' => $node->comment,
'promote' => $node->promote,
'moderate' => $node->moderate,
'sticky' => $node->sticky,
);
$node_table_types = array(
'nid' => '%d',
'vid' => '%d',
'title' => "'%s'",
'type' => "'%s'",
'uid' => '%d',
'status' => '%d',
'created' => '%d',
'changed' => '%d',
'comment' => '%d',
'promote' => '%d',
'moderate' => '%d',
'sticky' => '%d',
);
if ($node->is_new) {
$node_query = 'INSERT INTO {node} (' . implode(', ', array_keys($node_table_types)) . ') VALUES (' . implode(', ', $node_table_types) . ')';
$revisions_query = 'INSERT INTO {node_revisions} (' . implode(', ', array_keys($revisions_table_types)) . ') VALUES (' . implode(', ', $revisions_table_types) . ')';
}
else {
$arr = array();
foreach ($node_table_types as $key => $value) {
$arr[] = $key . ' = ' . $value;
}
$node_table_values[] = $node->nid;
$node_query = 'UPDATE {node} SET ' . implode(', ', $arr) . ' WHERE nid = %d';
if ($node->revision) {
$revisions_query = 'INSERT INTO {node_revisions} (' . implode(', ', array_keys($revisions_table_types)) . ') VALUES (' . implode(', ', $revisions_table_types) . ')';
}
else {
$arr = array();
foreach ($revisions_table_types as $key => $value) {
$arr[] = $key . ' = ' . $value;
}
$revisions_table_values[] = $node->vid;
$revisions_query = 'UPDATE {node_revisions} SET ' . implode(', ', $arr) . ' WHERE vid = %d';
}
}
db_query($node_query, $node_table_values);
db_query($revisions_query, $revisions_table_values);
if ($node->is_new) {
node_invoke($node, 'insert');
node_invoke_nodeapi($node, 'insert');
}
else {
node_invoke($node, 'update');
node_invoke_nodeapi($node, 'update');
}
cache_clear_all();
}
function node_view($node, $teaser = FALSE, $page = FALSE, $links = TRUE) {
$node = (object) $node;
$node->body = str_replace('<!--break-->', '', $node->body);
if ($node->log != '' && !$teaser && $node->moderate) {
$node->body .= '<div class="log"><div class="title">' . t('Log') . ':</div>' . filter_xss($node->log) . '</div>';
}
if (node_hook($node, 'view')) {
node_invoke($node, 'view', $teaser, $page);
}
else {
$node = node_prepare($node, $teaser);
}
node_invoke_nodeapi($node, 'view', $teaser, $page);
if ($links) {
$node->links = module_invoke_all('link', 'node', $node, !$page);
}
if ($teaser) {
unset($node->body);
}
else {
unset($node->teaser);
}
return theme('node', $node, $teaser, $page);
}
function node_prepare($node, $teaser = FALSE) {
$node->readmore = strlen($node->teaser) < strlen($node->body);
if ($teaser == FALSE) {
$node->body = check_markup($node->body, $node->format, FALSE);
}
else {
$node->teaser = check_markup($node->teaser, $node->format, FALSE);
}
return $node;
}
function node_show($node, $cid) {
$output = node_view($node, FALSE, TRUE);
if (function_exists('comment_render') && $node->comment) {
$output .= comment_render($node, $cid);
}
node_tag_new($node->nid);
return $output;
}
function node_perm() {
return array(
'administer nodes',
'access content',
'view revisions',
'revert revisions',
);
}
function node_search($op = 'search', $keys = null) {
switch ($op) {
case 'name':
return t('content');
case 'reset':
variable_del('node_cron_last');
variable_del('node_cron_last_nid');
return;
case 'status':
$last = variable_get('node_cron_last', 0);
$last_nid = variable_get('node_cron_last_nid', 0);
$total = db_result(db_query('SELECT COUNT(*) FROM {node} WHERE status = 1'));
$remaining = db_result(db_query('SELECT COUNT(*) FROM {node} n LEFT JOIN {node_comment_statistics} c ON n.nid = c.nid WHERE n.status = 1 AND ((GREATEST(n.created, n.changed, c.last_comment_timestamp) = %d AND n.nid > %d ) OR (n.created > %d OR n.changed > %d OR c.last_comment_timestamp > %d))', $last, $last_nid, $last, $last, $last));
return array(
'remaining' => $remaining,
'total' => $total,
);
case 'admin':
$form = array();
$form['content_ranking'] = array(
'#type' => 'fieldset',
'#title' => t('Content ranking'),
);
$form['content_ranking']['#theme'] = 'node_search_admin';
$form['content_ranking']['info'] = array(
'#type' => 'markup',
'#value' => '<em>' . t('The following numbers control which properties the content search should favor when ordering the results. Higher numbers mean more influence, zero means the property is ignored. Changing these numbers does not require the search index to be rebuilt. Changes take effect immediately.') . '</em>',
);
$ranking = array(
'node_rank_relevance' => t('Keyword relevance'),
'node_rank_recent' => t('Recently posted'),
);
if (module_exist('comment')) {
$ranking['node_rank_comments'] = t('Number of comments');
}
if (module_exist('statistics') && variable_get('statistics_count_content_views', 0)) {
$ranking['node_rank_views'] = t('Number of views');
}
$options = drupal_map_assoc(range(0, 10));
foreach ($ranking as $var => $title) {
$form['content_ranking']['factors'][$var] = array(
'#title' => $title,
'#type' => 'select',
'#options' => $options,
'#default_value' => variable_get($var, 5),
);
}
return $form;
case 'search':
list($join1, $where1) = _db_rewrite_sql();
$arguments1 = array();
$conditions1 = 'n.status = 1';
if ($type = search_query_extract($keys, 'type')) {
$types = array();
foreach (explode(',', $type) as $t) {
$types[] = "n.type = '%s'";
$arguments1[] = $t;
}
$conditions1 .= ' AND (' . implode(' OR ', $types) . ')';
$keys = search_query_insert($keys, 'type');
}
if ($category = search_query_extract($keys, 'category')) {
$categories = array();
foreach (explode(',', $category) as $c) {
$categories[] = "tn.tid = %d";
$arguments1[] = $c;
}
$conditions1 .= ' AND (' . implode(' OR ', $categories) . ')';
$join1 .= ' INNER JOIN {term_node} tn ON n.nid = tn.nid';
$keys = search_query_insert($keys, 'category');
}
$ranking = array();
$arguments2 = array();
$join2 = '';
$total = 0;
$stats_join = false;
if ($weight = (int) variable_get('node_rank_relevance', 5)) {
$ranking[] = '%d * i.relevance';
$arguments2[] = $weight;
$total += $weight;
}
if ($weight = (int) variable_get('node_rank_recent', 5)) {
$ranking[] = '%d * POW(2, (GREATEST(n.created, n.changed, c.last_comment_timestamp) - %d) * 6.43e-8)';
$arguments2[] = $weight;
$arguments2[] = (int) variable_get('node_cron_last', 0);
$join2 .= ' INNER JOIN {node} n ON n.nid = i.sid LEFT JOIN {node_comment_statistics} c ON c.nid = i.sid';
$stats_join = true;
$total += $weight;
}
if (module_exist('comment') && ($weight = (int) variable_get('node_rank_comments', 5))) {
$scale = variable_get('node_cron_comments_scale', 0.0);
$ranking[] = '%d * (2.0 - 2.0 / (1.0 + c.comment_count * %f))';
$arguments2[] = $weight;
$arguments2[] = $scale;
if (!$stats_join) {
$join2 .= ' LEFT JOIN {node_comment_statistics} c ON c.nid = i.sid';
}
$total += $weight;
}
if (module_exist('statistics') && variable_get('statistics_count_content_views', 0) && ($weight = (int) variable_get('node_rank_views', 5))) {
$scale = variable_get('node_cron_views_scale', 0.0);
$ranking[] = '%d * (2.0 - 2.0 / (1.0 + nc.totalcount * %f))';
$arguments2[] = $weight;
$arguments2[] = $scale;
$join2 .= ' LEFT JOIN {node_counter} nc ON nc.nid = i.sid';
$total += $weight;
}
$select2 = (count($ranking) ? implode(' + ', $ranking) : 'i.relevance') . ' AS score';
$find = do_search($keys, 'node', 'INNER JOIN {node} n ON n.nid = i.sid ' . $join1 . ' INNER JOIN {users} u ON n.uid = u.uid', $conditions1 . (empty($where1) ? '' : ' AND ' . $where1), $arguments1, $select2, $join2, $arguments2);
$results = array();
foreach ($find as $item) {
$node = node_load($item->sid);
if (node_hook($node, 'view')) {
node_invoke($node, 'view', false, false);
}
else {
$node = node_prepare($node, false);
}
node_invoke_nodeapi($node, 'view', false, false);
$node->body .= module_invoke('comment', 'nodeapi', $node, 'update index');
$node->body .= module_invoke('taxonomy', 'nodeapi', $node, 'update index');
$extra = node_invoke_nodeapi($node, 'search result');
$results[] = array(
'link' => url('node/' . $item->sid),
'type' => node_get_name($node),
'title' => $node->title,
'user' => theme('username', $node),
'date' => $node->changed,
'node' => $node,
'extra' => $extra,
'score' => $item->score / $total,
'snippet' => search_excerpt($keys, $node->body),
);
}
return $results;
}
}
function node_user($op, &$edit, &$user) {
if ($op == 'delete') {
db_query('UPDATE {node} SET uid = 0 WHERE uid = %d', $user->uid);
db_query('UPDATE {node_revisions} SET uid = 0 WHERE uid = %d', $user->uid);
}
}
function theme_node_search_admin($form) {
$output = form_render($form['info']);
$header = array(
t('Factor'),
t('Weight'),
);
foreach (element_children($form['factors']) as $key) {
$row = array();
$row[] = $form['factors'][$key]['#title'];
unset($form['factors'][$key]['#title']);
$row[] = form_render($form['factors'][$key]);
$rows[] = $row;
}
$output .= theme('table', $header, $rows);
$output .= form_render($form);
return $output;
}
function node_configure() {
$form['default_nodes_main'] = array(
'#type' => 'select',
'#title' => t('Number of posts on main page'),
'#default_value' => variable_get('default_nodes_main', 10),
'#options' => drupal_map_assoc(array(
1,
2,
3,
4,
5,
6,
7,
8,
9,
10,
15,
20,
25,
30,
)),
'#description' => t('The default maximum number of posts to display per page on overview pages such as the main page.'),
);
$form['teaser_length'] = array(
'#type' => 'select',
'#title' => t('Length of trimmed posts'),
'#default_value' => variable_get('teaser_length', 600),
'#options' => array(
0 => t('Unlimited'),
200 => t('200 characters'),
400 => t('400 characters'),
600 => t('600 characters'),
800 => t('800 characters'),
1000 => t('1000 characters'),
1200 => t('1200 characters'),
1400 => t('1400 characters'),
1600 => t('1600 characters'),
1800 => t('1800 characters'),
2000 => t('2000 characters'),
),
'#description' => t("The maximum number of characters used in the trimmed version of a post. Drupal will use this setting to determine at which offset long posts should be trimmed. The trimmed version of a post is typically used as a teaser when displaying the post on the main page, in XML feeds, etc. To disable teasers, set to 'Unlimited'. Note that this setting will only affect new or updated content and will not affect existing teasers."),
);
$form['node_preview'] = array(
'#type' => 'radios',
'#title' => t('Preview post'),
'#default_value' => variable_get('node_preview', 0),
'#options' => array(
t('Optional'),
t('Required'),
),
'#description' => t('Must users preview posts before submitting?'),
);
return system_settings_form('node_configure', $form);
}
function node_comment_mode($nid) {
static $comment_mode;
if (!isset($comment_mode[$nid])) {
$comment_mode[$nid] = db_result(db_query('SELECT comment FROM {node} WHERE nid = %d', $nid));
}
return $comment_mode[$nid];
}
function node_link($type, $node = 0, $main = 0) {
$links = array();
if ($type == 'node') {
if ($main == 1 && $node->teaser && $node->readmore) {
$links[] = l(t('read more'), "node/{$node->nid}", array(
'title' => t('Read the rest of this posting.'),
'class' => 'read-more',
));
}
}
return $links;
}
function node_menu($may_cache) {
$items = array();
if ($may_cache) {
$items[] = array(
'path' => 'admin/node',
'title' => t('content'),
'callback' => 'node_admin_nodes',
'access' => user_access('administer nodes'),
);
$items[] = array(
'path' => 'admin/node/overview',
'title' => t('list'),
'type' => MENU_DEFAULT_LOCAL_TASK,
'weight' => -10,
);
if (module_exist('search')) {
$items[] = array(
'path' => 'admin/node/search',
'title' => t('search'),
'callback' => 'node_admin_search',
'access' => user_access('administer nodes'),
'type' => MENU_LOCAL_TASK,
);
}
$items[] = array(
'path' => 'admin/settings/node',
'title' => t('posts'),
'callback' => 'node_configure',
'access' => user_access('administer nodes'),
);
$items[] = array(
'path' => 'admin/settings/content-types',
'title' => t('content types'),
'callback' => 'node_types_configure',
'access' => user_access('administer nodes'),
);
$items[] = array(
'path' => 'node',
'title' => t('content'),
'callback' => 'node_page',
'access' => user_access('access content'),
'type' => MENU_MODIFIABLE_BY_ADMIN,
);
$items[] = array(
'path' => 'node/add',
'title' => t('create content'),
'callback' => 'node_page',
'access' => user_access('access content'),
'type' => MENU_ITEM_GROUPING,
'weight' => 1,
);
$items[] = array(
'path' => 'rss.xml',
'title' => t('rss feed'),
'callback' => 'node_feed',
'access' => user_access('access content'),
'type' => MENU_CALLBACK,
);
}
else {
if (arg(0) == 'node' && is_numeric(arg(1))) {
$node = node_load(arg(1));
if ($node->nid) {
$items[] = array(
'path' => 'node/' . arg(1),
'title' => t('view'),
'callback' => 'node_page',
'access' => node_access('view', $node),
'type' => MENU_CALLBACK,
);
$items[] = array(
'path' => 'node/' . arg(1) . '/view',
'title' => t('view'),
'type' => MENU_DEFAULT_LOCAL_TASK,
'weight' => -10,
);
$items[] = array(
'path' => 'node/' . arg(1) . '/edit',
'title' => t('edit'),
'callback' => 'node_page',
'access' => node_access('update', $node),
'weight' => 1,
'type' => MENU_LOCAL_TASK,
);
$items[] = array(
'path' => 'node/' . arg(1) . '/delete',
'title' => t('delete'),
'callback' => 'node_delete_confirm',
'access' => node_access('delete', $node),
'weight' => 1,
'type' => MENU_CALLBACK,
);
$revisions_access = (user_access('view revisions') || user_access('administer nodes')) && node_access('view', $node) && db_result(db_query('SELECT COUNT(vid) FROM {node_revisions} WHERE nid = %d', arg(1))) > 1;
$items[] = array(
'path' => 'node/' . arg(1) . '/revisions',
'title' => t('revisions'),
'callback' => 'node_revisions',
'access' => $revisions_access,
'weight' => 2,
'type' => MENU_LOCAL_TASK,
);
$items[] = array(
'path' => 'node/' . arg(1) . '/revisions/' . arg(3) . '/delete',
'title' => t('revisions'),
'callback' => 'node_revisions',
'access' => $revisions_access,
'weight' => 2,
'type' => MENU_CALLBACK,
);
$items[] = array(
'path' => 'node/' . arg(1) . '/revisions/' . arg(3) . '/revert',
'title' => t('revisions'),
'callback' => 'node_revisions',
'access' => $revisions_access,
'weight' => 2,
'type' => MENU_CALLBACK,
);
}
}
else {
if (arg(0) == 'admin' && arg(1) == 'settings' && arg(2) == 'content-types' && is_string(arg(3))) {
$items[] = array(
'path' => 'admin/settings/content-types/' . arg(3),
'title' => t("'%name' content type", array(
'%name' => node_get_name(arg(3)),
)),
'type' => MENU_CALLBACK,
);
}
}
}
return $items;
}
function node_last_changed($nid) {
$node = db_fetch_object(db_query('SELECT changed FROM {node} WHERE nid = %d', $nid));
return $node->changed;
}
function node_operations() {
$operations = array(
'approve' => array(
t('Approve the selected posts'),
'UPDATE {node} SET status = 1, moderate = 0 WHERE nid = %d',
),
'promote' => array(
t('Promote the selected posts'),
'UPDATE {node} SET status = 1, promote = 1, moderate = 0 WHERE nid = %d',
),
'sticky' => array(
t('Make the selected posts sticky'),
'UPDATE {node} SET status = 1, sticky = 1 WHERE nid = %d',
),
'demote' => array(
t('Demote the selected posts'),
'UPDATE {node} SET promote = 0 WHERE nid = %d',
),
'unpublish' => array(
t('Unpublish the selected posts'),
'UPDATE {node} SET status = 0 WHERE nid = %d',
),
'delete' => array(
t('Delete the selected posts'),
'',
),
);
return $operations;
}
function node_filters() {
$filters['status'] = array(
'title' => t('status'),
'options' => array(
'status-1' => t('published'),
'status-0' => t('not published'),
'moderate-1' => t('in moderation'),
'moderate-0' => t('not in moderation'),
'promote-1' => t('promoted'),
'promote-0' => t('not promoted'),
'sticky-1' => t('sticky'),
'sticky-0' => t('not sticky'),
),
);
$filters['type'] = array(
'title' => t('type'),
'options' => node_get_types(),
);
if ($taxonomy = module_invoke('taxonomy', 'form_all', 1)) {
$filters['category'] = array(
'title' => t('category'),
'options' => $taxonomy,
);
}
return $filters;
}
function node_build_filter_query() {
$filters = node_filters();
$where = $args = array();
$join = '';
foreach ($_SESSION['node_overview_filter'] as $index => $filter) {
list($key, $value) = $filter;
switch ($key) {
case 'status':
list($key, $value) = explode('-', $value, 2);
$where[] = 'n.' . $key . ' = %d';
break;
case 'category':
$table = "tn{$index}";
$where[] = "{$table}.tid = %d";
$join .= "INNER JOIN {term_node} {$table} ON n.nid = {$table}.nid ";
break;
case 'type':
$where[] = "n.type = '%s'";
}
$args[] = $value;
}
$where = count($where) ? 'WHERE ' . implode(' AND ', $where) : '';
return array(
'where' => $where,
'join' => $join,
'args' => $args,
);
}
function node_filter_form() {
$session =& $_SESSION['node_overview_filter'];
$session = is_array($session) ? $session : array();
$filters = node_filters();
$i = 0;
$form['filters'] = array(
'#type' => 'fieldset',
'#title' => t('Show only items where'),
'#theme' => 'node_filters',
);
foreach ($session as $filter) {
list($type, $value) = $filter;
if ($type == 'category') {
$value = module_invoke('taxonomy', 'get_term', $value);
$value = $value->name;
}
else {
$value = $filters[$type]['options'][$value];
}
$string = $i++ ? '<em>and</em> where <strong>%a</strong> is <strong>%b</strong>' : '<strong>%a</strong> is <strong>%b</strong>';
$form['filters']['current'][] = array(
'#value' => t($string, array(
'%a' => $filters[$type]['title'],
'%b' => $value,
)),
);
}
foreach ($filters as $key => $filter) {
$names[$key] = $filter['title'];
$form['filters']['status'][$key] = array(
'#type' => 'select',
'#options' => $filter['options'],
);
}
$form['filters']['filter'] = array(
'#type' => 'radios',
'#options' => $names,
'#default_value' => 'status',
);
$form['filters']['buttons']['submit'] = array(
'#type' => 'submit',
'#value' => count($session) ? t('Refine') : t('Filter'),
);
if (count($session)) {
$form['filters']['buttons']['undo'] = array(
'#type' => 'submit',
'#value' => t('Undo'),
);
$form['filters']['buttons']['reset'] = array(
'#type' => 'submit',
'#value' => t('Reset'),
);
}
return drupal_get_form('node_filter_form', $form);
}
function theme_node_filter_form(&$form) {
$output .= '<div id="node-admin-filter">';
$output .= form_render($form['filters']);
$output .= '</div>';
$output .= form_render($form);
return $output;
}
function theme_node_filters(&$form) {
$output .= '<ul>';
if (sizeof($form['current'])) {
foreach (element_children($form['current']) as $key) {
$output .= '<li>' . form_render($form['current'][$key]) . '</li>';
}
}
$output .= '<li><dl class="multiselect">' . (sizeof($form['current']) ? '<dt><em>' . t('and') . '</em> ' . t('where') . '</dt>' : '') . '<dd class="a">';
foreach (element_children($form['filter']) as $key) {
$output .= form_render($form['filter'][$key]);
}
$output .= '</dd>';
$output .= '<dt>' . t('is') . '</dt>' . '<dd class="b">';
foreach (element_children($form['status']) as $key) {
$output .= form_render($form['status'][$key]);
}
$output .= '</dd>';
$output .= '</dl>';
$output .= '<div class="container-inline" id="node-admin-buttons">' . form_render($form['buttons']) . '</div>';
$output .= '</li></ul><br class="clear" />';
return $output;
}
function node_filter_form_submit() {
global $form_values;
$op = $_POST['op'];
$filters = node_filters();
switch ($op) {
case t('Filter'):
case t('Refine'):
if (isset($form_values['filter'])) {
$filter = $form_values['filter'];
$flat_options = form_options_flatten($filters[$filter]['options']);
if (isset($flat_options[$form_values[$filter]])) {
$_SESSION['node_overview_filter'][] = array(
$filter,
$form_values[$filter],
);
}
}
break;
case t('Undo'):
array_pop($_SESSION['node_overview_filter']);
break;
case t('Reset'):
$_SESSION['node_overview_filter'] = array();
break;
}
}
function node_admin_nodes_submit($form_id, $edit) {
$operations = node_operations();
if ($operations[$edit['operation']][1]) {
$operation = $operations[$edit['operation']][1];
foreach ($edit['nodes'] as $nid => $value) {
if ($value) {
db_query($operation, $nid);
}
}
cache_clear_all();
drupal_set_message(t('The update has been performed.'));
}
}
function node_admin_nodes_validate($form_id, $edit) {
$edit['nodes'] = array_diff($edit['nodes'], array(
0,
));
if (count($edit['nodes']) == 0) {
if ($edit['operation'] == 'delete') {
form_set_error('', t('Please select some items to perform the delete operation.'));
}
else {
form_set_error('', t('Please select some items to perform the update on.'));
}
}
}
function node_admin_nodes() {
global $form_values;
$output = node_filter_form();
if ($_POST['edit']['operation'] == 'delete' && $_POST['edit']['nodes']) {
return node_multiple_delete_confirm();
}
$filter = node_build_filter_query();
$result = pager_query('SELECT n.*, u.name, u.uid FROM {node} n ' . $filter['join'] . ' INNER JOIN {users} u ON n.uid = u.uid ' . $filter['where'] . ' ORDER BY n.changed DESC', 50, 0, NULL, $filter['args']);
$form['options'] = array(
'#type' => 'fieldset',
'#title' => t('Update options'),
'#prefix' => '<div class="container-inline">',
'#suffix' => '</div>',
);
$options = array();
foreach (node_operations() as $key => $value) {
$options[$key] = $value[0];
}
$form['options']['operation'] = array(
'#type' => 'select',
'#options' => $options,
'#default_value' => 'approve',
);
$form['options']['submit'] = array(
'#type' => 'submit',
'#value' => t('Update'),
);
$destination = drupal_get_destination();
while ($node = db_fetch_object($result)) {
$nodes[$node->nid] = '';
$form['title'][$node->nid] = array(
'#value' => l($node->title, 'node/' . $node->nid) . ' ' . theme('mark', node_mark($node->nid, $node->changed)),
);
$form['name'][$node->nid] = array(
'#value' => node_get_name($node),
);
$form['username'][$node->nid] = array(
'#value' => theme('username', $node),
);
$form['status'][$node->nid] = array(
'#value' => $node->status ? t('published') : t('not published'),
);
$form['operations'][$node->nid] = array(
'#value' => l(t('edit'), 'node/' . $node->nid . '/edit', array(), $destination),
);
}
$form['nodes'] = array(
'#type' => 'checkboxes',
'#options' => $nodes,
);
$form['pager'] = array(
'#value' => theme('pager', NULL, 50, 0),
);
$output .= drupal_get_form('node_admin_nodes', $form);
return $output;
}
function theme_node_admin_nodes($form) {
$header = array(
NULL,
t('Title'),
t('Type'),
t('Author'),
t('Status'),
t('Operations'),
);
$output .= form_render($form['options']);
if (isset($form['title']) && is_array($form['title'])) {
foreach (element_children($form['title']) as $key) {
$row = array();
$row[] = form_render($form['nodes'][$key]);
$row[] = form_render($form['title'][$key]);
$row[] = form_render($form['name'][$key]);
$row[] = form_render($form['username'][$key]);
$row[] = form_render($form['status'][$key]);
$row[] = form_render($form['operations'][$key]);
$rows[] = $row;
}
}
else {
$rows[] = array(
array(
'data' => t('No posts available.'),
'colspan' => '6',
),
);
}
$output .= theme('table', $header, $rows);
if ($form['pager']['#value']) {
$output .= form_render($form['pager']);
}
$output .= form_render($form);
return $output;
}
function node_multiple_delete_confirm() {
$edit = $_POST['edit'];
$form['nodes'] = array(
'#prefix' => '<ul>',
'#suffix' => '</ul>',
'#tree' => TRUE,
);
foreach (array_filter($edit['nodes']) as $nid => $value) {
$title = db_result(db_query('SELECT title FROM {node} WHERE nid = %d', $nid));
$form['nodes'][$nid] = array(
'#type' => 'hidden',
'#value' => $nid,
'#prefix' => '<li>',
'#suffix' => check_plain($title) . "</li>\n",
);
}
$form['operation'] = array(
'#type' => 'hidden',
'#value' => 'delete',
);
return confirm_form('node_multiple_delete_confirm', $form, t('Are you sure you want to delete these items?'), 'admin/node', t('This action cannot be undone.'), t('Delete all'), t('Cancel'));
}
function node_multiple_delete_confirm_submit($form_id, $edit) {
if ($edit['confirm']) {
foreach ($edit['nodes'] as $nid => $value) {
node_delete($nid);
}
drupal_set_message(t('The items have been deleted.'));
}
return 'admin/node';
}
function node_types_configure($type = NULL) {
if (isset($type)) {
$node = new stdClass();
$node->type = $type;
$form['submission'] = array(
'#type' => 'fieldset',
'#title' => t('Submission form'),
);
$form['submission'][$type . '_help'] = array(
'#type' => 'textarea',
'#title' => t('Explanation or submission guidelines'),
'#default_value' => variable_get($type . '_help', ''),
'#description' => t('This text will be displayed at the top of the %type submission form. It is useful for helping or instructing your users.', array(
'%type' => node_get_name($type),
)),
);
$form['submission']['minimum_' . $type . '_size'] = array(
'#type' => 'select',
'#title' => t('Minimum number of words'),
'#default_value' => variable_get('minimum_' . $type . '_size', 0),
'#options' => drupal_map_assoc(array(
0,
10,
25,
50,
75,
100,
125,
150,
175,
200,
)),
'#description' => t('The minimum number of words a %type must be to be considered valid. This can be useful to rule out submissions that do not meet the site\'s standards, such as short test posts.', array(
'%type' => node_get_name($type),
)),
);
$form['workflow'] = array(
'#type' => 'fieldset',
'#title' => t('Workflow'),
);
$form['type'] = array(
'#type' => 'value',
'#value' => $type,
);
$form['array_filter'] = array(
'#type' => 'value',
'#value' => TRUE,
);
return system_settings_form($type . '_node_settings', $form);
}
else {
$header = array(
t('Type'),
t('Operations'),
);
$rows = array();
foreach (node_get_types() as $type => $name) {
$rows[] = array(
$name,
l(t('configure'), 'admin/settings/content-types/' . $type),
);
}
return theme('table', $header, $rows);
}
}
function node_revision_overview($node) {
drupal_set_title(t('Revisions for %title', array(
'%title' => check_plain($node->title),
)));
$header = array(
t('Revision'),
array(
'data' => t('Operations'),
'colspan' => 2,
),
);
$revisions = node_revision_list($node);
$rows = array();
$revert_permission = FALSE;
if ((user_access('revert revisions') || user_access('administer nodes')) && node_access('update', $node)) {
$revert_permission = TRUE;
}
$delete_permission = FALSE;
if (user_access('administer nodes')) {
$delete_permission = TRUE;
}
foreach ($revisions as $revision) {
$row = array();
$operations = array();
if ($revision->current_vid > 0) {
$row[] = array(
'data' => t('%date by %username', array(
'%date' => l(format_date($revision->timestamp, 'small'), "node/{$node->nid}"),
'%username' => theme('username', $revision),
)) . ($revision->log != '' ? '<p class="revision-log">' . filter_xss($revision->log) . '</p>' : ''),
'class' => 'revision-current',
);
$operations[] = array(
'data' => theme('placeholder', t('current revision')),
'class' => 'revision-current',
'colspan' => 2,
);
}
else {
$row[] = t('%date by %username', array(
'%date' => l(format_date($revision->timestamp, 'small'), "node/{$node->nid}/revisions/{$revision->vid}/view"),
'%username' => theme('username', $revision),
)) . ($revision->log != '' ? '<p class="revision-log">' . filter_xss($revision->log) . '</p>' : '');
if ($revert_permission) {
$operations[] = l(t('revert'), "node/{$node->nid}/revisions/{$revision->vid}/revert");
}
if ($delete_permission) {
$operations[] = l(t('delete'), "node/{$node->nid}/revisions/{$revision->vid}/delete");
}
}
$rows[] = array_merge($row, $operations);
}
$output .= theme('table', $header, $rows);
return $output;
}
function node_revision_revert($nid, $revision) {
global $user;
$node = node_load($nid, $revision);
if ((user_access('revert revisions') || user_access('administer nodes')) && node_access('update', $node)) {
if ($node->vid) {
$form = array();
$form['nid'] = array(
'#type' => 'value',
'#value' => $node->nid,
);
$form['vid'] = array(
'#type' => 'value',
'#value' => $node->vid,
);
return confirm_form('node_revision_revert_confirm', $form, t('Are you sure you want to revert %title to the revision from %revision-date?', array(
'%title' => theme('placeholder', $node->title),
'%revision-date' => theme('placeholder', format_date($node->revision_timestamp)),
)), "node/{$nid}/revisions", ' ', t('Revert'), t('Cancel'));
}
else {
drupal_set_message(t('You tried to revert to an invalid revision.'), 'error');
}
drupal_goto('node/' . $nid . '/revisions');
}
drupal_access_denied();
}
function node_revision_revert_confirm_submit($form_id, $form_values) {
$nid = $form_values['nid'];
$revision = $form_values['vid'];
$node = node_load($nid, $revision);
$node->revision = 1;
$node->log = t('Copy of the revision from %date.', array(
'%date' => theme('placeholder', format_date($node->revision_timestamp)),
));
if (module_exist('taxonomy')) {
$node->taxonomy = array_keys($node->taxonomy);
}
node_save($node);
drupal_set_message(t('%title has been reverted back to the revision from %revision-date', array(
'%revision-date' => theme('placeholder', format_date($node->revision_timestamp)),
'%title' => theme('placeholder', check_plain($node->title)),
)));
watchdog('content', t('%type: reverted %title revision %revision.', array(
'%type' => theme('placeholder', t($node->type)),
'%title' => theme('placeholder', $node->title),
'%revision' => theme('placeholder', $revision),
)));
return 'node/' . $nid . '/revisions';
}
function node_revision_delete($nid, $revision) {
if (user_access('administer nodes')) {
$node = node_load($nid);
if (node_access('delete', $node)) {
if ($revision != $node->vid) {
$node = node_load($nid, $revision);
$form = array();
$form['nid'] = array(
'#type' => 'value',
'#value' => $nid,
);
$form['vid'] = array(
'#type' => 'value',
'#value' => $revision,
);
return confirm_form('node_revision_delete_confirm', $form, t('Are you sure you want to delete %title revision %revision?', array(
'%title' => theme('placeholder', $node->title),
'%revision' => theme('placeholder', $revision),
)), "node/{$nid}/revisions", '', t('Delete'), t('Cancel'));
}
else {
drupal_set_message(t('Deletion failed. You tried to delete the current revision.'));
}
if (db_result(db_query('SELECT COUNT(vid) FROM {node_revisions} WHERE nid = %d', $nid)) > 1) {
drupal_goto("node/{$nid}/revisions");
}
else {
drupal_goto("node/{$nid}");
}
}
}
drupal_access_denied();
}
function node_revision_delete_confirm_submit($form_id, $form_values) {
$node = node_load($form_values['nid'], $form_values['vid']);
db_query("DELETE FROM {node_revisions} WHERE nid = %d AND vid = %d", $node->nid, $node->vid);
node_invoke_nodeapi($node, 'delete revision');
drupal_set_message(t('Deleted %title revision %revision.', array(
'%title' => theme('placeholder', $node->title),
'%revision' => theme('placeholder', $node->vid),
)));
watchdog('content', t('%type: deleted %title revision %revision.', array(
'%type' => theme('placeholder', t($node->type)),
'%title' => theme('placeholder', $node->title),
'%revision' => theme('placeholder', $node->revision),
)));
if (db_result(db_query('SELECT COUNT(vid) FROM {node_revisions} WHERE nid = %d', $node->nid)) > 1) {
return "node/{$node->nid}/revisions";
}
return "node/{$node->nid}";
}
function node_revision_list($node) {
$revisions = array();
$result = db_query('SELECT r.vid, r.title, r.log, r.uid, n.vid AS current_vid, r.timestamp, u.name FROM {node_revisions} r LEFT JOIN {node} n ON n.vid = r.vid INNER JOIN {users} u ON u.uid = r.uid WHERE r.nid = %d ORDER BY r.timestamp DESC', $node->nid);
while ($revision = db_fetch_object($result)) {
$revisions[] = $revision;
}
return $revisions;
}
function node_admin_search() {
$output = search_form(url('admin/node/search'), $_POST['edit']['keys'], 'node') . search_data($_POST['edit']['keys'], 'node');
return $output;
}
function node_block($op = 'list', $delta = 0) {
if ($op == 'list') {
$blocks[0]['info'] = t('Syndicate');
return $blocks;
}
else {
if ($op == 'view') {
$block['subject'] = t('Syndicate');
$block['content'] = theme('feed_icon', url('rss.xml'));
return $block;
}
}
}
function node_feed($nodes = 0, $channel = array()) {
global $base_url, $locale;
if (!$nodes) {
$nodes = db_query_range(db_rewrite_sql('SELECT n.nid, n.created FROM {node} n WHERE n.promote = 1 AND n.status = 1 ORDER BY n.created DESC'), 0, variable_get('feed_default_items', 10));
}
$item_length = variable_get('feed_item_length', 'teaser');
$namespaces = array(
'xmlns:dc="http://purl.org/dc/elements/1.1/"',
);
while ($node = db_fetch_object($nodes)) {
$item = node_load($node->nid);
$link = url("node/{$node->nid}", NULL, NULL, 1);
if ($item_length != 'title') {
$teaser = $item_length == 'teaser' ? TRUE : FALSE;
if (node_hook($item, 'view')) {
node_invoke($item, 'view', $teaser, FALSE);
}
else {
$item = node_prepare($item, $teaser);
}
node_invoke_nodeapi($item, 'view', $teaser, FALSE);
}
$extra = node_invoke_nodeapi($item, 'rss item');
$extra = array_merge($extra, array(
array(
'key' => 'pubDate',
'value' => date('r', $item->created),
),
array(
'key' => 'dc:creator',
'value' => $item->name,
),
array(
'key' => 'guid',
'value' => $item->nid . ' at ' . $base_url,
'attributes' => array(
'isPermaLink' => 'false',
),
),
));
foreach ($extra as $element) {
if ($element['namespace']) {
$namespaces = array_merge($namespaces, $element['namespace']);
}
}
switch ($item_length) {
case 'fulltext':
$item_text = $item->body;
break;
case 'teaser':
$item_text = $item->teaser;
if ($item->readmore) {
$item_text .= '<p>' . l(t('read more'), 'node/' . $item->nid, NULL, NULL, NULL, TRUE) . '</p>';
}
break;
case 'title':
$item_text = '';
break;
}
$items .= format_rss_item($item->title, $link, $item_text, $extra);
}
$channel_defaults = array(
'version' => '2.0',
'title' => variable_get('site_name', 'drupal') . ' - ' . variable_get('site_slogan', ''),
'link' => $base_url,
'description' => variable_get('site_mission', ''),
'language' => $locale,
);
$channel = array_merge($channel_defaults, $channel);
$output = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n";
$output .= "<rss version=\"" . $channel["version"] . "\" xml:base=\"" . $base_url . "\" " . implode(' ', $namespaces) . ">\n";
$output .= format_rss_channel($channel['title'], $channel['link'], $channel['description'], $items, $channel['language']);
$output .= "</rss>\n";
drupal_set_header('Content-Type: application/rss+xml; charset=utf-8');
print $output;
}
function node_submit($node) {
global $user;
$node = (object) $node;
if (!isset($node->teaser)) {
$node->teaser = isset($node->body) ? node_teaser($node->body, isset($node->format) ? $node->format : NULL) : '';
}
$access = user_access('administer nodes');
if ($access) {
if ($account = user_load(array(
'name' => $node->name,
))) {
$node->uid = $account->uid;
}
else {
$node->uid = 0;
}
$node->created = $node->date ? strtotime($node->date) : NULL;
}
$node_options = variable_get('node_options_' . $node->type, array(
'status',
'promote',
));
foreach (array(
'status',
'moderate',
'promote',
'sticky',
'revision',
) as $key) {
if (!$access || !isset($node->{$key})) {
$node->{$key} = in_array($key, $node_options);
}
}
node_invoke($node, 'submit');
node_invoke_nodeapi($node, 'submit');
$node->validated = TRUE;
return $node;
}
function node_validate($node, $form = array()) {
$node = (object) $node;
if (isset($node->body) && count(explode(' ', $node->body)) < variable_get('minimum_' . $node->type . '_size', 0)) {
form_set_error('body', t('The body of your %type is too short. You need at least %words words.', array(
'%words' => variable_get('minimum_' . $node->type . '_size', 0),
'%type' => node_get_name($node),
)));
}
if (isset($node->nid) && node_last_changed($node->nid) > $node->changed) {
form_set_error('changed', t('This content has been modified by another user, changes cannot be saved.'));
}
if (user_access('administer nodes')) {
if (!empty($node->name) && !($account = user_load(array(
'name' => $node->name,
)))) {
form_set_error('name', t('The username %name does not exist.', array(
'%name' => theme('placeholder', $node->name),
)));
}
if (!empty($node->date) && strtotime($node->date) <= 0) {
form_set_error('date', t('You have to specify a valid date.'));
}
}
node_invoke($node, 'validate', $form);
node_invoke_nodeapi($node, 'validate', $form);
}
function node_form_validate($form_id, $form_values, $form) {
node_validate($form_values, $form);
}
function node_object_prepare(&$node) {
if (user_access('administer nodes')) {
if (!isset($node->created)) {
$node->created = time();
}
if (!isset($node->date)) {
$node->date = format_date($node->created, 'custom', 'Y-m-d H:i:s O');
}
}
node_invoke($node, 'prepare');
node_invoke_nodeapi($node, 'prepare');
}
function node_form($node) {
$node = (object) $node;
$form = node_form_array($node);
return drupal_get_form($node->type . '_node_form', $form, 'node_form');
}
function node_form_array($node) {
node_object_prepare($node);
$form['#id'] = 'node-form';
foreach (array(
'nid',
'vid',
'uid',
'created',
'type',
) as $key) {
$form[$key] = array(
'#type' => 'value',
'#value' => $node->{$key},
);
}
$form['changed'] = array(
'#type' => 'hidden',
'#default_value' => $node->changed,
);
$form = array_merge_recursive($form, node_invoke($node, 'form'));
if (!isset($form['title']['#weight'])) {
$form['title']['#weight'] = -5;
}
$node_options = variable_get('node_options_' . $node->type, array(
'status',
'promote',
));
if (!isset($node->nid)) {
foreach (array(
'status',
'moderate',
'promote',
'sticky',
'revision',
) as $key) {
$node->{$key} = in_array($key, $node_options);
}
global $user;
$node->uid = $user->uid;
}
else {
$node->revision = in_array('revision', $node_options);
}
$form['#node'] = $node;
if (user_access('administer nodes')) {
$form['author'] = array(
'#type' => 'fieldset',
'#title' => t('Authoring information'),
'#collapsible' => TRUE,
'#collapsed' => TRUE,
'#weight' => 20,
);
$form['author']['name'] = array(
'#type' => 'textfield',
'#title' => t('Authored by'),
'#maxlength' => 60,
'#autocomplete_path' => 'user/autocomplete',
'#default_value' => $node->name ? $node->name : '',
'#weight' => -1,
'#description' => t('Leave blank for %anonymous.', array(
'%anonymous' => theme('placeholder', variable_get('anonymous', 'Anonymous')),
)),
);
$form['author']['date'] = array(
'#type' => 'textfield',
'#title' => t('Authored on'),
'#maxlength' => 25,
'#description' => t('Format: %time. Leave blank to use the time of form submission.', array(
'%time' => $node->date,
)),
);
if (isset($node->nid)) {
$form['author']['date']['#default_value'] = $node->date;
}
$form['options'] = array(
'#type' => 'fieldset',
'#title' => t('Publishing options'),
'#collapsible' => TRUE,
'#collapsed' => TRUE,
'#weight' => 25,
);
$form['options']['status'] = array(
'#type' => 'checkbox',
'#title' => t('Published'),
'#default_value' => $node->status,
);
$form['options']['moderate'] = array(
'#type' => 'checkbox',
'#title' => t('In moderation queue'),
'#default_value' => $node->moderate,
);
$form['options']['promote'] = array(
'#type' => 'checkbox',
'#title' => t('Promoted to front page'),
'#default_value' => $node->promote,
);
$form['options']['sticky'] = array(
'#type' => 'checkbox',
'#title' => t('Sticky at top of lists'),
'#default_value' => $node->sticky,
);
$form['options']['revision'] = array(
'#type' => 'checkbox',
'#title' => t('Create new revision'),
'#default_value' => $node->revision,
);
}
else {
foreach (array(
'uid',
'created',
) as $key) {
$form[$key] = array(
'#type' => 'value',
'#value' => $node->{$key},
);
}
}
$form['preview'] = array(
'#type' => 'button',
'#value' => t('Preview'),
'#weight' => 40,
);
$form['submit'] = array(
'#type' => 'submit',
'#value' => t('Submit'),
'#weight' => 45,
);
if ($node->nid && node_access('delete', $node)) {
$form['delete'] = array(
'#type' => 'button',
'#value' => t('Delete'),
'#weight' => 50,
);
}
$form['#after_build'] = array(
'node_form_add_preview',
);
return $form;
}
function node_form_add_preview($form) {
global $form_values;
$op = isset($_POST['op']) ? $_POST['op'] : '';
if ($op == t('Preview')) {
drupal_validate_form($form['form_id']['#value'], $form);
if (!form_get_errors()) {
$preview = node_preview((object) $form_values);
$form['#prefix'] = isset($form['#prefix']) ? $preview . $form['#prefix'] : $preview;
}
}
if (variable_get('node_preview', 0) && (form_get_errors() || $op != t('Preview'))) {
unset($form['submit']);
}
return $form;
}
function theme_node_form($form) {
$output = "\n<div class=\"node-form\">\n";
$admin = '';
if (isset($form['author'])) {
$admin .= " <div class=\"authored\">\n";
$admin .= form_render($form['author']);
$admin .= " </div>\n";
}
if (isset($form['options'])) {
$admin .= " <div class=\"options\">\n";
$admin .= form_render($form['options']);
$admin .= " </div>\n";
}
$buttons = form_render($form['preview']);
$buttons .= form_render($form['submit']);
$buttons .= isset($form['delete']) ? form_render($form['delete']) : '';
$output .= " <div class=\"standard\">\n";
$output .= form_render($form);
$output .= " </div>\n";
if (!empty($admin)) {
$output .= " <div class=\"admin\">\n";
$output .= $admin;
$output .= " </div>\n";
}
$output .= $buttons;
$output .= "</div>\n";
return $output;
}
function node_add($type) {
global $user;
if (array_key_exists($type, node_get_types()) && node_access('create', $type)) {
$node = array(
'uid' => $user->uid,
'name' => $user->name,
'type' => $type,
);
$output = node_form($node);
drupal_set_title(t('Submit %name', array(
'%name' => node_get_name($node),
)));
}
else {
foreach (node_get_types() as $type => $name) {
if (node_access('create', $type)) {
$out = '<dt>' . l($name, "node/add/{$type}", array(
'title' => t('Add a new %s.', array(
'%s' => $name,
)),
)) . '</dt>';
$out .= '<dd>' . implode("\n", module_invoke_all('help', 'node/add#' . $type)) . '</dd>';
$item[$name] = $out;
}
}
if (isset($item)) {
uksort($item, 'strnatcasecmp');
$output = t('Choose the appropriate item from the list:') . '<dl>' . implode('', $item) . '</dl>';
}
else {
$output = t('You are not allowed to create content.');
}
}
return $output;
}
function node_preview($node) {
if (node_access('create', $node) || node_access('update', $node)) {
if (isset($node->name)) {
if ($user = user_load(array(
'name' => $node->name,
))) {
$node->uid = $user->uid;
$node->picture = $user->picture;
}
else {
$node->uid = 0;
}
}
else {
if ($node->uid) {
$user = user_load(array(
'uid' => $node->uid,
));
$node->name = $user->name;
$node->picture = $user->picture;
}
}
if ($node->date) {
$node->created = strtotime($node->date);
}
$node->changed = time();
if (!isset($node->teaser)) {
$node->teaser = node_teaser($node->body, $node->format);
}
if (!form_get_errors()) {
$cloned_node = drupal_clone($node);
$cloned_node->in_preview = TRUE;
$output = theme('node_preview', $cloned_node);
}
drupal_set_title(t('Preview'));
drupal_set_breadcrumb(array(
l(t('Home'), NULL),
l(t('create content'), 'node/add'),
l(t('Submit %name', array(
'%name' => node_get_name($node),
)), 'node/add/' . $node->type),
));
return $output;
}
}
function theme_node_preview($node) {
$output = '<div class="preview">';
if ($node->teaser && $node->teaser != $node->body) {
drupal_set_message(t('The trimmed version of your post shows what your post looks like when promoted to the main page or when exported for syndication. You can insert the delimiter "<!--break-->" (without the quotes) to fine-tune where your post gets split.'));
$output .= '<h3>' . t('Preview trimmed version') . '</h3>';
$output .= node_view(drupal_clone($node), 1, FALSE, 0);
$output .= '<h3>' . t('Preview full version') . '</h3>';
$output .= node_view($node, 0, FALSE, 0);
}
else {
$output .= node_view($node, 0, FALSE, 0);
}
$output .= "</div>\n";
return $output;
}
function node_form_submit($form_id, $edit) {
global $user;
$node = node_submit($edit);
if ($node->nid) {
$original_node = node_load($node->nid);
if (node_access('update', $original_node)) {
node_save($node);
watchdog('content', t('%type: updated %title.', array(
'%type' => theme('placeholder', t($node->type)),
'%title' => theme('placeholder', $node->title),
)), WATCHDOG_NOTICE, l(t('view'), 'node/' . $node->nid));
drupal_set_message(t('The %post was updated.', array(
'%post' => node_get_name($node),
)));
}
}
else {
if (node_access('create', $node)) {
node_save($node);
watchdog('content', t('%type: added %title.', array(
'%type' => theme('placeholder', t($node->type)),
'%title' => theme('placeholder', $node->title),
)), WATCHDOG_NOTICE, l(t('view'), "node/{$node->nid}"));
drupal_set_message(t('Your %post was created.', array(
'%post' => node_get_name($node),
)));
}
}
if ($node->nid) {
if (node_access('view', $node)) {
return 'node/' . $node->nid;
}
else {
return '';
}
}
return FALSE;
}
function node_delete_confirm() {
$edit = $_POST['edit'];
$edit['nid'] = $edit['nid'] ? $edit['nid'] : arg(1);
$node = node_load($edit['nid']);
if (node_access('delete', $node)) {
$form['nid'] = array(
'#type' => 'value',
'#value' => $node->nid,
);
$output = confirm_form('node_delete_confirm', $form, t('Are you sure you want to delete %title?', array(
'%title' => theme('placeholder', $node->title),
)), $_GET['destination'] ? $_GET['destination'] : 'node/' . $node->nid, t('This action cannot be undone.'), t('Delete'), t('Cancel'));
}
return $output;
}
function node_delete_confirm_submit($form_id, $form_values) {
if ($form_values['confirm']) {
node_delete($form_values['nid']);
}
return '';
}
function node_delete($nid) {
$node = node_load($nid);
if (node_access('delete', $node)) {
db_query('DELETE FROM {node} WHERE nid = %d', $node->nid);
db_query('DELETE FROM {node_revisions} WHERE nid = %d', $node->nid);
node_invoke($node, 'delete');
node_invoke_nodeapi($node, 'delete');
cache_clear_all();
if (function_exists('search_wipe')) {
search_wipe($node->nid, 'node');
}
drupal_set_message(t('%title has been deleted.', array(
'%title' => theme('placeholder', $node->title),
)));
watchdog('content', t('%type: deleted %title.', array(
'%type' => theme('placeholder', t($node->type)),
'%title' => theme('placeholder', $node->title),
)));
}
}
function node_revisions() {
if (is_numeric(arg(1)) && arg(2) == 'revisions') {
$op = arg(4) ? arg(4) : 'overview';
switch ($op) {
case 'overview':
$node = node_load(arg(1));
if ((user_access('view revisions') || user_access('administer nodes')) && node_access('view', $node)) {
return node_revision_overview($node);
}
drupal_access_denied();
return;
case 'view':
if (is_numeric(arg(3))) {
$node = node_load(arg(1), arg(3));
if ($node->nid) {
if ((user_access('view revisions') || user_access('administer nodes')) && node_access('view', $node)) {
drupal_set_title(t('Revision of %title from %date', array(
'%title' => theme('placeholder', $node->title),
'%date' => format_date($node->revision_timestamp),
)));
return node_show($node, arg(2));
}
drupal_access_denied();
return;
}
}
break;
case 'revert':
return node_revision_revert(arg(1), arg(3));
break;
case 'delete':
return node_revision_delete(arg(1), arg(3));
break;
}
}
drupal_not_found();
}
function node_page_default() {
$result = pager_query(db_rewrite_sql('SELECT n.nid, n.sticky, n.created FROM {node} n WHERE n.promote = 1 AND n.status = 1 ORDER BY n.sticky DESC, n.created DESC'), variable_get('default_nodes_main', 10));
if (db_num_rows($result)) {
drupal_add_link(array(
'rel' => 'alternate',
'type' => 'application/rss+xml',
'title' => t('RSS'),
'href' => url('rss.xml', NULL, NULL, TRUE),
));
$output = '';
while ($node = db_fetch_object($result)) {
$output .= node_view(node_load($node->nid), 1);
}
$output .= theme('pager', NULL, variable_get('default_nodes_main', 10));
}
else {
$output = t('
<h1 class="title">Welcome to your new Drupal website!</h1>
<p>Please follow these steps to set up and start using your website:</p>
<ol>
<li>
<strong>Create your administrator account</strong>
To begin, <a href="%register">create the first account</a>. This account will have full administration rights and will allow you to configure your website.
</li>
<li>
<strong>Configure your website</strong>
Once logged in, visit the <a href="%admin">administration section</a>, where you can <a href="%config">customize and configure</a> all aspects of your website.
</li>
<li>
<strong>Enable additional functionality</strong>
Next, visit the <a href="%modules">module list</a> and enable features which suit your specific needs. You can find additional modules in the <a href="%download_modules">Drupal modules download section</a>.
</li>
<li>
<strong>Customize your website design</strong>
To change the "look and feel" of your website, visit the <a href="%themes">themes section</a>. You may choose from one of the included themes or download additional themes from the <a href="%download_themes">Drupal themes download section</a>.
</li>
<li>
<strong>Start posting content</strong>
Finally, you can <a href="%content">create content</a> for your website. This message will disappear once you have published your first post.
</li>
</ol>
<p>For more information, please refer to the <a href="%help">Help section</a>, or the <a href="%handbook">online Drupal handbooks</a>. You may also post at the <a href="%forum">Drupal forum</a>, or view the wide range of <a href="%support">other support options</a> available.</p>', array(
'%drupal' => 'http://drupal.org/',
'%register' => url('user/register'),
'%admin' => url('admin'),
'%config' => url('admin/settings'),
'%modules' => url('admin/modules'),
'%download_modules' => 'http://drupal.org/project/modules',
'%themes' => url('admin/themes'),
'%download_themes' => 'http://drupal.org/project/themes',
'%content' => url('node/add'),
'%help' => url('admin/help'),
'%handbook' => 'http://drupal.org/handbooks',
'%forum' => 'http://drupal.org/forum',
'%support' => 'http://drupal.org/support',
));
$output = '<div id="first-time">' . $output . '</div>';
}
return $output;
}
function node_page() {
$op = arg(1);
if (is_numeric($op)) {
$op = arg(2) && !is_numeric(arg(2)) ? arg(2) : 'view';
}
switch ($op) {
case 'view':
if (is_numeric(arg(1))) {
$node = node_load(arg(1));
if ($node->nid) {
drupal_set_title(check_plain($node->title));
return node_show($node, arg(2));
}
else {
if (db_result(db_query('SELECT nid FROM {node} WHERE nid = %d', arg(1)))) {
drupal_access_denied();
}
else {
drupal_not_found();
}
}
}
break;
case 'add':
return node_add(arg(2));
break;
case 'edit':
if ($_POST['op'] == t('Delete')) {
if ($_REQUEST['destination']) {
$destination = drupal_get_destination();
unset($_REQUEST['destination']);
}
drupal_goto('node/' . arg(1) . '/delete', $destination);
}
if (is_numeric(arg(1))) {
$node = node_load(arg(1));
if ($node->nid) {
drupal_set_title(check_plain($node->title));
return node_form($node);
}
else {
if (db_result(db_query('SELECT nid FROM {node} WHERE nid = %d', arg(1)))) {
drupal_access_denied();
}
else {
drupal_not_found();
}
}
}
break;
default:
drupal_set_title('');
return node_page_default();
}
}
function node_update_shutdown() {
global $last_change, $last_nid;
if ($last_change && $last_nid) {
variable_set('node_cron_last', $last_change);
variable_set('node_cron_last_nid', $last_nid);
}
}
function node_update_index() {
global $last_change, $last_nid;
register_shutdown_function('node_update_shutdown');
$last = variable_get('node_cron_last', 0);
$last_nid = variable_get('node_cron_last_nid', 0);
$limit = (int) variable_get('search_cron_limit', 100);
variable_set('node_cron_comments_scale', 1.0 / max(1, db_result(db_query('SELECT MAX(comment_count) FROM {node_comment_statistics}'))));
variable_set('node_cron_views_scale', 1.0 / max(1, db_result(db_query('SELECT MAX(totalcount) FROM {node_counter}'))));
$result = db_query_range('SELECT GREATEST(IF(c.last_comment_timestamp IS NULL, 0, c.last_comment_timestamp), n.changed) as last_change, n.nid FROM {node} n LEFT JOIN {node_comment_statistics} c ON n.nid = c.nid WHERE n.status = 1 AND ((GREATEST(n.changed, c.last_comment_timestamp) = %d AND n.nid > %d) OR (n.changed > %d OR c.last_comment_timestamp > %d)) ORDER BY GREATEST(n.changed, c.last_comment_timestamp) ASC, n.nid ASC', $last, $last_nid, $last, $last, $last, 0, $limit);
while ($node = db_fetch_object($result)) {
$last_change = $node->last_change;
$last_nid = $node->nid;
$node = node_load($node->nid);
if (node_hook($node, 'view')) {
node_invoke($node, 'view', false, false);
}
else {
$node = node_prepare($node, false);
}
node_invoke_nodeapi($node, 'view', false, false);
$text = '<h1>' . check_plain($node->title) . '</h1>' . $node->body;
$extra = node_invoke_nodeapi($node, 'update index');
foreach ($extra as $t) {
$text .= $t;
}
search_index($node->nid, 'node', $text);
}
}
function node_form_alter($form_id, &$form) {
if (isset($form['type']) && $form['type']['#value'] . '_node_settings' == $form_id) {
$form['workflow']['node_options_' . $form['type']['#value']] = array(
'#type' => 'checkboxes',
'#title' => t('Default options'),
'#default_value' => variable_get('node_options_' . $form['type']['#value'], array(
'status',
'promote',
)),
'#options' => array(
'status' => t('Published'),
'moderate' => t('In moderation queue'),
'promote' => t('Promoted to front page'),
'sticky' => t('Sticky at top of lists'),
'revision' => t('Create new revision'),
),
'#description' => t('Users with the <em>administer nodes</em> permission will be able to override these options.'),
);
}
elseif ($form_id == 'search_form' && arg(1) == 'node') {
$form['advanced'] = array(
'#type' => 'fieldset',
'#title' => t('Advanced search'),
'#collapsible' => TRUE,
'#collapsed' => TRUE,
'#attributes' => array(
'class' => 'search-advanced',
),
);
$form['advanced']['keywords'] = array(
'#prefix' => '<div class="criterion">',
'#suffix' => '</div>',
);
$form['advanced']['keywords']['or'] = array(
'#type' => 'textfield',
'#title' => t('Containing any of the words'),
'#size' => 30,
'#maxlength' => 255,
);
$form['advanced']['keywords']['phrase'] = array(
'#type' => 'textfield',
'#title' => t('Containing the phrase'),
'#size' => 30,
'#maxlength' => 255,
);
$form['advanced']['keywords']['negative'] = array(
'#type' => 'textfield',
'#title' => t('Containing none of the words'),
'#size' => 30,
'#maxlength' => 255,
);
if ($taxonomy = module_invoke('taxonomy', 'form_all', 1)) {
$form['advanced']['category'] = array(
'#type' => 'select',
'#title' => t('Only in the category(s)'),
'#prefix' => '<div class="criterion">',
'#size' => 10,
'#suffix' => '</div>',
'#options' => $taxonomy,
'#multiple' => TRUE,
);
}
$types = node_get_types();
$form['advanced']['type'] = array(
'#type' => 'checkboxes',
'#title' => t('Only of the type(s)'),
'#prefix' => '<div class="criterion">',
'#suffix' => '</div>',
'#options' => $types,
);
$form['advanced']['submit'] = array(
'#type' => 'submit',
'#value' => t('Advanced search'),
'#prefix' => '<div class="action">',
'#suffix' => '</div><br class="clear" />',
);
$form['#validate']['node_search_validate'] = array();
}
}
function node_search_validate($form_id, $form_values, $form) {
$keys = $form_values['processed_keys'];
if (isset($form_values['type']) && is_array($form_values['type'])) {
$form_values['type'] = array_filter($form_values['type']);
if (count($form_values['type'])) {
$keys = search_query_insert($keys, 'type', implode(',', array_keys($form_values['type'])));
}
}
if (isset($form_values['category']) && is_array($form_values['category'])) {
$keys = search_query_insert($keys, 'category', implode(',', $form_values['category']));
}
if ($form_values['or'] != '') {
if (preg_match_all('/ ("[^"]+"|[^" ]+)/i', ' ' . $form_values['or'], $matches)) {
$keys .= ' ' . implode(' OR ', $matches[1]);
}
}
if ($form_values['negative'] != '') {
if (preg_match_all('/ ("[^"]+"|[^" ]+)/i', ' ' . $form_values['negative'], $matches)) {
$keys .= ' -' . implode(' -', $matches[1]);
}
}
if ($form_values['phrase'] != '') {
$keys .= ' "' . str_replace('"', ' ', $form_values['phrase']) . '"';
}
if (!empty($keys)) {
form_set_value($form['basic']['inline']['processed_keys'], trim($keys));
}
}
function node_access($op, $node = NULL, $uid = NULL) {
if ($op != 'create') {
$node = (object) $node;
}
if ($op == 'update' && !filter_access($node->format)) {
return FALSE;
}
if (user_access('administer nodes')) {
return TRUE;
}
if (!user_access('access content')) {
return FALSE;
}
$access = module_invoke(node_get_base($node), 'access', $op, $node);
if (!is_null($access)) {
return $access;
}
if ($op != 'create' && $node->nid && $node->status) {
$grants = array();
foreach (node_access_grants($op, $uid) as $realm => $gids) {
foreach ($gids as $gid) {
$grants[] = "(gid = {$gid} AND realm = '{$realm}')";
}
}
$grants_sql = '';
if (count($grants)) {
$grants_sql = 'AND (' . implode(' OR ', $grants) . ')';
}
$sql = "SELECT COUNT(*) FROM {node_access} WHERE (nid = 0 OR nid = %d) {$grants_sql} AND grant_{$op} >= 1";
$result = db_query($sql, $node->nid);
return db_result($result);
}
return FALSE;
}
function _node_access_join_sql($node_alias = 'n', $node_access_alias = 'na') {
if (user_access('administer nodes')) {
return '';
}
return 'INNER JOIN {node_access} ' . $node_access_alias . ' ON ' . $node_access_alias . '.nid = ' . $node_alias . '.nid';
}
function _node_access_where_sql($op = 'view', $node_access_alias = 'na', $uid = NULL) {
if (user_access('administer nodes')) {
return;
}
$grants = array();
foreach (node_access_grants($op, $uid) as $realm => $gids) {
foreach ($gids as $gid) {
$grants[] = "({$node_access_alias}.gid = {$gid} AND {$node_access_alias}.realm = '{$realm}')";
}
}
$grants_sql = '';
if (count($grants)) {
$grants_sql = 'AND (' . implode(' OR ', $grants) . ')';
}
$sql = "{$node_access_alias}.grant_{$op} >= 1 {$grants_sql}";
return $sql;
}
function node_access_grants($op, $uid = NULL) {
global $user;
if (isset($uid)) {
$user_object = user_load(array(
'uid' => $uid,
));
}
else {
$user_object = $user;
}
return array_merge(array(
'all' => array(
0,
),
), module_invoke_all('node_grants', $user_object, $op));
}
function node_access_view_all_nodes() {
static $access;
if (!isset($access)) {
$grants = array();
foreach (node_access_grants('view') as $realm => $gids) {
foreach ($gids as $gid) {
$grants[] = "(gid = {$gid} AND realm = '{$realm}')";
}
}
$grants_sql = '';
if (count($grants)) {
$grants_sql = 'AND (' . implode(' OR ', $grants) . ')';
}
$sql = "SELECT COUNT(*) FROM {node_access} WHERE nid = 0 {$grants_sql} AND grant_view >= 1";
$result = db_query($sql);
$access = db_result($result);
}
return $access;
}
function node_db_rewrite_sql($query, $primary_table, $primary_field) {
if ($primary_field == 'nid' && !node_access_view_all_nodes()) {
$return['join'] = _node_access_join_sql($primary_table);
$return['where'] = _node_access_where_sql();
$return['distinct'] = 1;
return $return;
}
}