'. t('All content in a website is stored and treated as nodes. 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.') .'
'; $output .= ''. 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.') .'
'; $output .= t('Node module features
'. t('For more information please read the configuration and customization handbook Node page.', array('@node' => 'http://drupal.org/handbook/modules/node/')) .'
'; return $output; case 'admin/content/search': return ''. t('Enter a simple pattern to search for a post. Words are matched exactly. Phrases can be surrounded by quotes to do an exact search.') .'
'; case 'admin/content/types': return ''. t('Below is a list of all the content types on your site. All posts that exist on your site are instances of one of these content types.') .'
'; case 'admin/content/types/add': return ''. t('To create a new content type, enter the human-readable name, the machine-readable name, and all other relevant fields that are on this page. Once created, users of your site will be able to create posts that are instances of this content type.') .'
'; } if (arg(0) == 'node' && is_numeric(arg(1)) && arg(2) == 'revisions') { return ''. t('The revisions let you track differences between multiple versions of a post.') .'
'; } if (arg(0) == 'node' && arg(1) == 'add' && $type = arg(2)) { $type = node_get_types('type', str_replace('-', '_', arg(2))); return ''. (isset($type->help) ? filter_xss_admin($type->help) : '') .'
'; } } /** * Implementation of hook_theme() */ function node_theme() { return array( '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), ), 'node_filters' => array( 'arguments' => array('form' => NULL), ), 'node_admin_nodes' => array( 'arguments' => array('form' => NULL), ), 'node_form' => array( 'arguments' => array('form' => NULL), ), 'node_preview' => array( 'arguments' => array('node' => NULL), ), 'node_log_message' => array( 'arguments' => array('log' => NULL), ), ); } /** * Implementation of hook_cron(). */ function node_cron() { db_query('DELETE FROM {history} WHERE timestamp < %d', NODE_NEW_LIMIT); } /** * Gather a listing of links to nodes. * * @param $result * A DB result object from a query to fetch node objects. If your query joins thenode_comment_statistics
table so that the comment_count
field is available, a title attribute will be added to show the number of comments.
* @param $title
* A heading for the resulting list.
*
* @return
* An HTML list suitable as content for a block.
*/
function node_title_list($result, $title = NULL) {
while ($node = db_fetch_object($result)) {
$items[] = l($node->title, 'node/'. $node->nid, !empty($node->comment_count) ? array('title' => format_plural($node->comment_count, '1 comment', '@count comments')) : array());
}
return theme('node_list', $items, $title);
}
/**
* Format a listing of links to nodes.
*/
function theme_node_list($items, $title = NULL) {
return theme('item_list', $items, $title);
}
/**
* Update the 'last viewed' timestamp of the specified node for current user.
*/
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());
}
}
}
/**
* Retrieves the timestamp at which the current user last viewed the
* specified node.
*/
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 = %d AND nid = %d", $user->uid, $nid));
}
return (isset($history[$nid]->timestamp) ? $history[$nid]->timestamp : 0);
}
/**
* 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.
* @return
* One of the MARK constants.
*/
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;
}
/**
* See if the user used JS to submit a teaser.
*/
function node_teaser_js(&$form, $form_values, &$form_state) {
// Glue the teaser to the body.
if (isset($form['#post']['teaser_js'])) {
if (trim($form_values['teaser_js'])) {
// Space the teaser from the body
$body = trim($form_values['teaser_js']) ."\r\n\r\n". trim($form_values['body']);
}
else {
// Empty teaser, no spaces.
$body = ''. $form_values['body'];
}
// Pass value onto preview/submit
form_set_value($form['body'], $body, $form_state);
// Pass value back onto form
$form['body']['#value'] = $body;
}
return $form;
}
/**
* Automatically generate a teaser for a node body in a given format.
*/
function node_teaser($body, $format = NULL) {
$size = variable_get('teaser_length', 600);
// Find where the delimiter is in the body
$delimiter = strpos($body, '');
// If the size is zero, and there is no delimiter, the entire body is the teaser.
if ($size == 0 && $delimiter === FALSE) {
return $body;
}
// If a valid delimiter has been specified, use it to chop off the teaser.
if ($delimiter !== FALSE) {
return substr($body, 0, $delimiter);
}
// We check for the presence of the PHP evaluator filter in the current
// format. If the body contains PHP code, we do not split it up to prevent
// parse errors.
if (isset($format)) {
$filters = filter_list_format($format);
if (isset($filters['filter/1']) && strpos($body, '') !== FALSE) {
return $body;
}
}
// If we have a short body, the entire body is the teaser.
if (strlen($body) < $size) {
return $body;
}
// The teaser may not be longer than maximum length specified. Initial slice.
$teaser = truncate_utf8($body, $size);
$position = 0;
// Cache the reverse of the teaser.
$reversed = strrev($teaser);
// In some cases, no delimiter has been specified. In this case, we try to
// split at paragraph boundaries.
$breakpoints = array('' => 0, ''. t('If the site is experiencing problems with permissions to content, you may have to rebuild the permissions cache. Possible causes for permission problems are disabling modules or configuration changes to permissions. Rebuilding will remove all privileges to posts, and replace them with permissions based on the current modules and settings.') .'
'; $status .= ''. t('Rebuilding may take some time if there is a lot of content or complex permission settings. After rebuilding has completed posts will automatically use the new permissions.') .'
'; $form['access'] = array('#type' => 'fieldset', '#title' => t('Node access status')); $form['access']['status'] = array('#value' => $status); $form['access']['rebuild'] = array('#type' => 'submit', '#value' => t('Rebuild permissions')); } $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($form); } /** * Form validate callback. */ function node_configure_validate($form, &$form_state, $form_values) { if ($form_values['op'] == t('Rebuild permissions')) { drupal_goto('admin/content/node-settings/rebuild'); } } /** * Menu callback: confirm rebuilding of permissions. */ function node_configure_rebuild_confirm() { return confirm_form(array(), t('Are you sure you want to rebuild node permissions on the site?'), 'admin/content/node-settings', t('This will wipe all current node permissions and rebuild them based on current settings. Rebuilding the permissions may take a while so please be patient. This action cannot be undone.'), t('Rebuild permissions'), t('Cancel')); } /** * Handler for wipe confirmation */ function node_configure_rebuild_confirm_submit(&$form, $form, &$form_state) { node_access_rebuild(); drupal_set_message(t('The node access table has been rebuilt.')); $form_state['redirect'] = 'admin/content/node-settings'; return; } /** * Retrieve the comment mode for the given node ID (none, read, or read/write). */ 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]; } /** * Implementation of hook_link(). */ function node_link($type, $node = NULL, $teaser = FALSE) { $links = array(); if ($type == 'node') { if ($teaser == 1 && $node->teaser && $node->readmore) { $links['node_read_more'] = array( 'title' => t('Read more'), 'href' => "node/$node->nid", 'attributes' => array('title' => t('Read the rest of this posting.')) ); } } return $links; } function _node_revision_access($node) { return (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', $node->nid)) > 1; } /** * Implementation of hook_menu(). */ function node_menu() { $items['admin/content'] = array( 'title' => 'Content management', 'description' => "Manage your site's content.", 'position' => 'left', 'weight' => -10, 'page callback' => 'system_admin_menu_block_page', 'access arguments' => array('administer site configuration'), 'file' => 'system.admin.inc', 'file path' => drupal_get_path('module', 'system'), ); $items['admin/content/node'] = array( 'title' => 'Content', 'description' => "View, edit, and delete your site's content.", 'page callback' => 'node_admin_content', 'access arguments' => array('administer nodes'), ); $items['admin/content/node/overview'] = array( 'title' => 'List', 'type' => MENU_DEFAULT_LOCAL_TASK, 'weight' => -10, ); if (module_exists('search')) { $items['admin/content/search'] = array( 'title' => 'Search content', 'description' => 'Search content by keyword.', 'page callback' => 'node_admin_search', 'access arguments' => array('administer nodes'), ); } $items['admin/content/node-settings'] = array( 'title' => 'Post settings', 'description' => 'Control posting behavior, such as teaser length, requiring previews before posting, and the number of posts on the front page.', 'page callback' => 'drupal_get_form', 'page arguments' => array('node_configure'), 'access arguments' => array('administer nodes'), ); $items['admin/content/node-settings/rebuild'] = array( 'title' => 'Rebuild permissions', 'page arguments' => array('node_configure_rebuild_confirm'), 'type' => MENU_CALLBACK, ); $items['admin/content/types'] = array( 'title' => 'Content types', 'description' => 'Manage posts by content type, including default status, front page promotion, etc.', 'page callback' => 'node_overview_types', 'access arguments' => array('administer content types'), ); $items['admin/content/types/list'] = array( 'title' => 'List', 'type' => MENU_DEFAULT_LOCAL_TASK, 'weight' => -10, ); $items['admin/content/types/add'] = array( 'title' => 'Add content type', 'page callback' => 'drupal_get_form', 'page arguments' => array('node_type_form'), 'type' => MENU_LOCAL_TASK, ); $items['node'] = array( 'title' => 'Content', 'page callback' => 'node_page_default', 'access arguments' => array('access content'), 'type' => MENU_MODIFIABLE_BY_ADMIN, ); $items['node/add'] = array( 'title' => 'Create content', 'page callback' => 'system_admin_menu_block_page', 'access callback' => '_node_add_access', 'weight' => 1, 'file' => 'system.admin.inc', 'file path' => drupal_get_path('module', 'system'), ); $items['rss.xml'] = array( 'title' => 'RSS feed', 'page callback' => 'node_feed', 'access arguments' => array('access content'), 'type' => MENU_CALLBACK, ); foreach (node_get_types() as $type) { if (function_exists($type->module .'_form')) { $name = check_plain($type->name); $type_url_str = str_replace('_', '-', $type->type); $items['node/add/'. $type_url_str] = array( 'title' => drupal_ucfirst($name), 'page callback' => 'node_add', 'page arguments' => array(2), 'access callback' => 'node_access', 'access arguments' => array('create', $type->type), 'description' => $type->description, ); $items['admin/content/types/'. $type_url_str] = array( 'title' => $type->name, 'page callback' => 'drupal_get_form', 'page arguments' => array('node_type_form', $type), 'type' => MENU_CALLBACK, ); $items['admin/content/types/'. $type_url_str .'/delete'] = array( 'title' => 'Delete', 'page arguments' => array('node_type_delete_confirm', $type), 'type' => MENU_CALLBACK, ); } } $items['node/%node'] = array( 'title' => 'View', 'page callback' => 'node_page_view', 'page arguments' => array(1), 'access callback' => 'node_access', 'access arguments' => array('view', 1), 'type' => MENU_CALLBACK); $items['node/%node/view'] = array( 'title' => 'View', 'type' => MENU_DEFAULT_LOCAL_TASK, 'weight' => -10); $items['node/%node/edit'] = array( 'title' => 'Edit', 'page callback' => 'node_page_edit', 'page arguments' => array(1), 'access callback' => 'node_access', 'access arguments' => array('update', 1), 'weight' => 1, 'type' => MENU_LOCAL_TASK); $items['node/%node/delete'] = array( 'title' => 'Delete', 'page callback' => 'drupal_get_form', 'page arguments' => array('node_delete_confirm', 1), 'access callback' => 'node_access', 'access arguments' => array('delete', 1), 'weight' => 1, 'type' => MENU_CALLBACK); $items['node/%node/revisions'] = array( 'title' => 'Revisions', 'page callback' => 'node_revisions', 'access callback' => '_node_revision_access', 'access arguments' => array(1), 'weight' => 2, 'type' => MENU_LOCAL_TASK, ); return $items; } function node_init() { if (arg(0) == 'admin' && arg(1) == 'content' && arg(2) == 'types') { include_once './'. drupal_get_path('module', 'node') .'/content_types.inc'; } drupal_add_css(drupal_get_path('module', 'node') .'/node.css'); } function node_last_changed($nid) { $node = db_fetch_object(db_query('SELECT changed FROM {node} WHERE nid = %d', $nid)); return ($node->changed); } /** * Implementation of hook_node_operations(). */ function node_node_operations() { $operations = array( 'publish' => array( 'label' => t('Publish'), 'callback' => 'node_operations_publish', ), 'unpublish' => array( 'label' => t('Unpublish'), 'callback' => 'node_operations_unpublish', ), 'promote' => array( 'label' => t('Promote to front page'), 'callback' => 'node_operations_promote', ), 'demote' => array( 'label' => t('Demote from front page'), 'callback' => 'node_operations_demote', ), 'sticky' => array( 'label' => t('Make sticky'), 'callback' => 'node_operations_sticky', ), 'unsticky' => array( 'label' => t('Remove stickiness'), 'callback' => 'node_operations_unsticky', ), 'delete' => array( 'label' => t('Delete'), ), ); return $operations; } /** * Callback function for admin mass publishing nodes. */ function node_operations_publish($nodes) { db_query('UPDATE {node} SET status = 1 WHERE nid IN(%s)', implode(',', $nodes)); } /** * Callback function for admin mass unpublishing nodes. */ function node_operations_unpublish($nodes) { db_query('UPDATE {node} SET status = 0 WHERE nid IN(%s)', implode(',', $nodes)); } /** * Callback function for admin mass promoting nodes. */ function node_operations_promote($nodes) { db_query('UPDATE {node} SET status = 1, promote = 1 WHERE nid IN(%s)', implode(',', $nodes)); } /** * Callback function for admin mass demoting nodes. */ function node_operations_demote($nodes) { db_query('UPDATE {node} SET promote = 0 WHERE nid IN(%s)', implode(',', $nodes)); } /** * Callback function for admin mass editing nodes to be sticky. */ function node_operations_sticky($nodes) { db_query('UPDATE {node} SET status = 1, sticky = 1 WHERE nid IN(%s)', implode(',', $nodes)); } /** * Callback function for admin mass editing nodes to remove stickiness. */ function node_operations_unsticky($nodes) { db_query('UPDATE {node} SET sticky = 0 WHERE nid IN(%s)', implode(',', $nodes)); } /** * List node administration filters that can be applied. */ function node_filters() { // Regular filters $filters['status'] = array('title' => t('status'), 'options' => array('status-1' => t('published'), 'status-0' => t('not published'), '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('names')); // The taxonomy filter if ($taxonomy = module_invoke('taxonomy', 'form_all', 1)) { $filters['category'] = array('title' => t('category'), 'options' => $taxonomy); } // Language filter if there is a list of languages if ($languages = module_invoke('locale', 'language_list')) { $languages = array('' => t('Language neutral')) + $languages; $filters['language'] = array('title' => t('language'), 'options' => $languages); } return $filters; } /** * Build query for node administration filters based on session. */ function node_build_filter_query() { $filters = node_filters(); // Build query $where = $args = array(); $join = ''; foreach ($_SESSION['node_overview_filter'] as $index => $filter) { list($key, $value) = $filter; switch ($key) { case 'status': // Note: no exploitable hole as $key/$value have already been checked when submitted 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'"; case 'language': $where[] = "n.language = '%s'"; } $args[] = $value; } $where = count($where) ? 'WHERE '. implode(' AND ', $where) : ''; return array('where' => $where, 'join' => $join, 'args' => $args); } /** * Return form for node administration filters. */ 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') { // Load term name from DB rather than search and parse options array. $value = module_invoke('taxonomy', 'get_term', $value); $value = $value->name; } else if ($type == 'language') { $value = empty($value) ? t('Language neutral') : module_invoke('locale', 'language_name', $value); } else { $value = $filters[$type]['options'][$value]; } if ($i++) { $form['filters']['current'][] = array('#value' => t('and where %a is %b', array('%a' => $filters[$type]['title'], '%b' => $value))); } else { $form['filters']['current'][] = array('#value' => t('%a is %b', array('%a' => $filters[$type]['title'], '%b' => $value))); } if (in_array($type, array('type', 'language'))) { // Remove the option if it is already being filtered on. unset($filters[$type]); } } 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 $form; } /** * Theme node administration filter form. */ function theme_node_filter_form($form) { $output = ''; $output .= ''. filter_xss($revision->log) .'
' : ''), '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 != '') ? ''. filter_xss($revision->log) .'
' : ''); 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); } return theme('table', $header, $rows); } /** * Revert to the revision with the specified revision number. A node and nodeapi "update" event is triggered * (via the node_save() call) when a revision is reverted. */ 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) { $node->revision = 1; $node->log = t('Copy of the revision from %date.', array('%date' => format_date($node->revision_timestamp))); if (module_exists('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' => format_date($node->revision_timestamp), '%title' => $node->title))); watchdog('content', '@type: reverted %title revision %revision.', array('@type' => $node->type, '%title' => $node->title, '%revision' => $revision)); } else { drupal_set_message(t('You tried to revert to an invalid revision.'), 'error'); } drupal_goto('node/'. $nid .'/revisions'); } drupal_access_denied(); } /** * Delete the revision with specified revision number. A "delete revision" nodeapi event is invoked when a * revision is deleted. */ function node_revision_delete($nid, $revision) { if (user_access('administer nodes')) { $node = node_load($nid); if (node_access('delete', $node)) { // Don't delete the current revision if ($revision != $node->vid) { $node = node_load($nid, $revision); db_query("DELETE FROM {node_revisions} WHERE nid = %d AND vid = %d", $nid, $revision); node_invoke_nodeapi($node, 'delete revision'); drupal_set_message(t('Deleted %title revision %revision.', array('%title' => $node->title, '%revision' => $revision))); watchdog('content', '@type: deleted %title revision %revision.', array('@type' => $node->type, '%title' => $node->title, '%revision' => $revision)); } 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(); } /** * Return a list of all the existing revision numbers. */ 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->vid] = $revision; } return $revisions; } function node_admin_search() { $keys = isset($_POST['keys']) ? $_POST['keys'] : NULL; return drupal_get_form('search_form', url('admin/content/search'), $keys, 'node') . search_data($keys, 'node'); } /** * Implementation of hook_block(). */ 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'), t('Syndicate')); return $block; } } /** * A generic function for generating RSS feeds from a set of nodes. * * @param $nodes * An object as returned by db_query() which contains the nid field. * @param $channel * An associative array containing title, link, description and other keys. * The link should be an absolute URL. */ function node_feed($nodes = 0, $channel = array()) { global $base_url, $language; 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/"'); $items = ''; while ($node = db_fetch_object($nodes)) { // Load the specified node: $item = node_load($node->nid); $link = url("node/$node->nid", array('absolute' => TRUE)); if ($item_length != 'title') { $teaser = ($item_length == 'teaser') ? TRUE : FALSE; // Filter and prepare node teaser if (node_hook($item, 'view')) { $item = node_invoke($item, 'view', $teaser, FALSE); } else { $item = node_prepare($item, $teaser); } // Allow modules to change $node->teaser before viewing. node_invoke_nodeapi($item, 'view', $teaser, FALSE); } // Allow modules to add additional item fields and/or modify $item $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 (isset($element['namespace'])) { $namespaces = array_merge($namespaces, $element['namespace']); } } // Prepare the item description switch ($item_length) { case 'fulltext': $item_text = $item->body; break; case 'teaser': $item_text = $item->teaser; if ($item->readmore) { $item_text .= ''. l(t('read more'), 'node/'. $item->nid, array('absolute' => TRUE)) .'
'; } 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' => $language->language ); $channel = array_merge($channel_defaults, $channel); $output = "\n"; $output .= "Please follow these steps to set up and start using your website:
'); $default_message .= ''. t('For more information, please refer to the help section, or the online Drupal handbooks. You may also post at the Drupal forum, or view the wide range of other support options available.', array('@help' => url('admin/help'), '@handbook' => 'http://drupal.org/handbooks', '@forum' => 'http://drupal.org/forum', '@support' => 'http://drupal.org/support')) .'
'; $output = '