? .patch ? dr.patch ? drbm.tmproj ? drupal_render.patch ? mw.patch ? tmp.patch ? tmp.patch.patch ? modules/node/node-admin-display-overview-form.tpl.php ? modules/node/node.build_mode.inc ? sites/all/modules ? sites/default/files Index: index.php =================================================================== RCS file: /cvs/drupal/drupal/index.php,v retrieving revision 1.96 diff -u -F^f -p -r1.96 index.php --- index.php 20 Sep 2008 20:22:23 -0000 1.96 +++ index.php 2 Jan 2009 14:10:57 -0000 @@ -21,7 +21,7 @@ require_once DRUPAL_ROOT . '/includes/bo drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL); $return = menu_execute_active_handler(); -// Menu status constants are integers; page content is a string. +// Menu status constants are integers; page content is a string or array. if (is_int($return)) { switch ($return) { case MENU_NOT_FOUND: @@ -36,8 +36,8 @@ if (is_int($return)) { } } elseif (isset($return)) { - // Print any value (including an empty string) except NULL or undefined: - print theme('page', $return); + // Print anything besides a menu constant, assuming it's not NULL or undefined. + drupal_render_page($return); } drupal_page_footer(); Index: includes/common.inc =================================================================== RCS file: /cvs/drupal/drupal/includes/common.inc,v retrieving revision 1.841 diff -u -F^f -p -r1.841 common.inc --- includes/common.inc 30 Dec 2008 16:43:14 -0000 1.841 +++ includes/common.inc 2 Jan 2009 14:10:58 -0000 @@ -301,8 +301,7 @@ function drupal_get_destination() { * Drupal will ensure that messages set by drupal_set_message() and other * session data are written to the database before the user is redirected. * - * This function ends the request; use it rather than a print theme('page') - * statement in your menu callback. + * This function ends the request; use it rather than returning an array in your menu callback. * * @param $path * A Drupal path or a full URL. @@ -389,7 +388,10 @@ function drupal_not_found() { } // To conserve CPU and bandwidth, omit the blocks. - print theme('page', $return, FALSE); + print drupal_render_page(array( + '#markup' => $return, + '#show_blocks' => FALSE + )); } /** @@ -416,7 +418,12 @@ function drupal_access_denied() { drupal_set_title(t('Access denied')); $return = t('You are not authorized to access this page.'); } - print theme('page', $return); + + // To conserve CPU and bandwidth, omit the blocks. + print drupal_render_page(array( + '#markup' => $return, + '#show_blocks' => FALSE + )); } /** @@ -821,7 +828,11 @@ function _drupal_log_error($error, $fata drupal_set_header($_SERVER['SERVER_PROTOCOL'] . ' Service unavailable'); drupal_set_title(t('Error')); if (!defined('MAINTENANCE_MODE') && drupal_get_bootstrap_phase() == DRUPAL_BOOTSTRAP_FULL) { - print theme('page', t('The website encountered an unexpected error. Please try again later.'), FALSE); + // To conserve CPU and bandwidth, omit the blocks. + print drupal_render_page(array( + '#markup' => t('The website encountered an unexpected error. Please try again later.'), + '#show_blocks' => FALSE + )); } else { print theme('maintenance_page', t('The website encountered an unexpected error. Please try again later.'), FALSE); @@ -3176,6 +3187,22 @@ function drupal_alter($type, &$data) { } /** + * Renders the page and adds all theming. + * + * @param $content + * A string or array representing the content of the page. + */ +function drupal_render_page($content) { + // The preferred return value of a menu callback is an array. + if (!is_array($content)) { + $content = array('content' => array('#markup' => $content)); + } + $content['#type'] = 'page'; + drupal_alter('page', $content); + print drupal_render($content); +} + +/** * Renders HTML given a structured array tree. * * Recursively iterates over each of the array elements, generating HTML code. @@ -3339,7 +3366,7 @@ function drupal_common_theme() { 'arguments' => array('text' => NULL) ), 'page' => array( - 'arguments' => array('content' => NULL, 'show_blocks' => TRUE, 'show_messages' => TRUE), + 'arguments' => array('content' => NULL), 'template' => 'page', ), 'maintenance_page' => array( @@ -3398,6 +3425,9 @@ function drupal_common_theme() { 'item_list' => array( 'arguments' => array('items' => array(), 'title' => NULL, 'type' => 'ul', 'attributes' => NULL), ), + 'list' => array( + 'arguments' => array('elements' => NULL), + ), 'more_help_link' => array( 'arguments' => array('url' => NULL), ), Index: includes/theme.inc =================================================================== RCS file: /cvs/drupal/drupal/includes/theme.inc,v retrieving revision 1.458 diff -u -F^f -p -r1.458 theme.inc --- includes/theme.inc 31 Dec 2008 12:02:21 -0000 1.458 +++ includes/theme.inc 2 Jan 2009 14:10:58 -0000 @@ -1571,6 +1571,28 @@ function theme_item_list($items = array( } /** + * Return a themed list of items from a drupal_render() style array. + * + * @param $elements + * An array consisting of the following keys: + * - #items. An array of items as expected by theme('item_list'). Mandatory. + * - #title. A title which prints above the list. Optional. + * - #list_type. The type of list to return. Defaults to "ul". + * - #attributes. An array of attributes as expected by theme('item_list'). Optional. + * @return + * A string containing the list output. + */ +function theme_list($elements) { + // Populate any missing array elements with their defaults. + $elements += array( + '#title' => '', + '#list_type' => 'ul', + '#attributes' => array(), + '#items' => array(), + ); + return theme('item_list', $elements['#items'], $elements['#title'], $elements['#list_type'], $elements['#attributes']); +} +/** * Returns code that emits the 'more help'-link. */ function theme_more_help_link($url) { @@ -1825,6 +1847,13 @@ function template_preprocess(&$variables * @see page.tpl.php */ function template_preprocess_page(&$variables) { + // Move some variables to the top level for themer convenience and template cleanliness. + $names = array('show_blocks' => TRUE, 'show_messages' => TRUE); + foreach ($names as $name => $default) { + $variables[$name] = isset($variables['content'][$name]) ? $variables['content'][$name] : $default; + } + $variables['content'] = &$variables['content']['#children']; + // Add favicon if (theme_get_setting('toggle_favicon')) { drupal_set_html_head(''); @@ -1977,6 +2006,8 @@ function template_preprocess_page(&$vari * @see node.tpl.php */ function template_preprocess_node(&$variables) { + $variables['teaser'] = &$variables['elements']['teaser']; + $variables['node'] = &$variables['elements']['node']; $node = $variables['node']; $variables['date'] = format_date($node->created); Index: modules/blog/blog.pages.inc =================================================================== RCS file: /cvs/drupal/drupal/modules/blog/blog.pages.inc,v retrieving revision 1.14 diff -u -F^f -p -r1.14 blog.pages.inc --- modules/blog/blog.pages.inc 13 Oct 2008 00:33:01 -0000 1.14 +++ modules/blog/blog.pages.inc 2 Jan 2009 14:10:58 -0000 @@ -23,18 +23,20 @@ function blog_page_user($account) { $items[] = t('You are not allowed to post a new blog entry.'); } - $output = theme('item_list', $items); - - $result = pager_query(db_rewrite_sql("SELECT n.nid, n.sticky, n.created FROM {node} n WHERE n.type = 'blog' AND n.uid = %d AND n.status = 1 ORDER BY n.sticky DESC, n.created DESC"), variable_get('default_nodes_main', 10), 0, NULL, $account->uid); - $has_posts = FALSE; - - while ($node = db_fetch_object($result)) { - $output .= node_view(node_load($node->nid), 1); - $has_posts = TRUE; - } - - if ($has_posts) { - $output .= theme('pager', NULL, variable_get('default_nodes_main', 10)); + $page['blog_actions'] = array( + '#items' => $items, + '#theme' => 'list', + '#weight' => -1, + ); + + $nids = pager_query(db_rewrite_sql("SELECT n.nid FROM {node} n WHERE n.type = 'blog' AND n.uid = %d AND n.status = 1 ORDER BY n.sticky DESC, n.created DESC"), variable_get('default_nodes_main', 10), 0, NULL, $account->uid)->fetchCol(); + if (!empty($nids)) { + $nodes = node_load_multiple($nids); + $page += node_build_multiple($nodes); + $page['pager'] = array( + '#markup' => theme('pager', NULL, variable_get('default_nodes_main', 10)), + '#weight' => count($nodes), + ); } else { if ($account->uid == $user->uid) { @@ -46,7 +48,7 @@ function blog_page_user($account) { } drupal_add_feed(url('blog/' . $account->uid . '/feed'), t('RSS - !title', array('!title' => $title))); - return $output; + return $page; } /** @@ -56,31 +58,33 @@ function blog_page_last() { global $user; $output = ''; - $items = array(); + $page = array(); if (user_access('edit own blog')) { $items[] = l(t('Create new blog entry.'), "node/add/blog"); - } - - $output = theme('item_list', $items); - - $result = pager_query(db_rewrite_sql("SELECT n.nid, n.created FROM {node} n WHERE n.type = 'blog' AND n.status = 1 ORDER BY n.sticky DESC, n.created DESC"), variable_get('default_nodes_main', 10)); - $has_posts = FALSE; - - while ($node = db_fetch_object($result)) { - $output .= node_view(node_load($node->nid), 1); - $has_posts = TRUE; - } - - if ($has_posts) { - $output .= theme('pager', NULL, variable_get('default_nodes_main', 10)); + $page['blog_actions'] = array( + '#items' => $items, + '#theme' => 'list', + '#weight' => -1, + ); + } + + $nids = pager_query(db_rewrite_sql("SELECT n.nid FROM {node} n WHERE n.type = 'blog' AND n.status = 1 ORDER BY n.sticky DESC, n.created DESC"), variable_get('default_nodes_main', 10))->fetchCol(); + + if (!empty($nids)) { + $nodes = node_load_multiple($nids); + $page += node_build_multiple($nodes); + $page['pager'] = array( + '#markup' => theme('pager', NULL, variable_get('default_nodes_main', 10)), + '#weight' => count($nodes), + ); } else { drupal_set_message(t('No blog entries have been created.')); } drupal_add_feed(url('blog/feed'), t('RSS - blogs')); - return $output; + return $page; } /** Index: modules/comment/comment.module =================================================================== RCS file: /cvs/drupal/drupal/modules/comment/comment.module,v retrieving revision 1.677 diff -u -F^f -p -r1.677 comment.module --- modules/comment/comment.module 31 Dec 2008 12:04:36 -0000 1.677 +++ modules/comment/comment.module 2 Jan 2009 14:10:58 -0000 @@ -1628,7 +1628,7 @@ function comment_form_add_preview($form, } else { $suffix = empty($form['#suffix']) ? '' : $form['#suffix']; - $form['#suffix'] = $suffix . node_view($node); + $form['#suffix'] = $suffix . drupal_render(node_view($node)); $edit['pid'] = 0; } Index: modules/comment/comment.pages.inc =================================================================== RCS file: /cvs/drupal/drupal/modules/comment/comment.pages.inc,v retrieving revision 1.11 diff -u -F^f -p -r1.11 comment.pages.inc --- modules/comment/comment.pages.inc 31 Dec 2008 12:02:21 -0000 1.11 +++ modules/comment/comment.pages.inc 2 Jan 2009 14:10:58 -0000 @@ -92,7 +92,7 @@ function comment_reply($node, $pid = NUL } // This is the case where the comment is in response to a node. Display the node. elseif (user_access('access content')) { - $output .= node_view($node); + $output .= drupal_render(node_view($node)); } // Should we show the reply box? Index: modules/node/node.api.php =================================================================== RCS file: /cvs/drupal/drupal/modules/node/node.api.php,v retrieving revision 1.6 diff -u -F^f -p -r1.6 node.api.php --- modules/node/node.api.php 31 Dec 2008 12:02:22 -0000 1.6 +++ modules/node/node.api.php 2 Jan 2009 14:10:58 -0000 @@ -169,7 +169,7 @@ function hook_node_operations() { * @return * None. */ -function hook_nodeapi_alter($node, $teaser, $page) { +function hook_nodeapi_alter($node, $teaser) { } /** Index: modules/node/node.module =================================================================== RCS file: /cvs/drupal/drupal/modules/node/node.module,v retrieving revision 1.1008 diff -u -F^f -p -r1.1008 node.module --- modules/node/node.module 31 Dec 2008 12:02:22 -0000 1.1008 +++ modules/node/node.module 2 Jan 2009 14:10:59 -0000 @@ -96,7 +96,7 @@ function node_help($path, $arg) { function node_theme() { return array( 'node' => array( - 'arguments' => array('node' => NULL, 'teaser' => FALSE, 'page' => FALSE), + 'arguments' => array('elements' => NULL), 'template' => 'node', ), 'node_list' => array( @@ -1123,24 +1123,28 @@ function node_delete($nid) { } /** - * Generate a display of the given node. + * Generate an array for rendering the given node. * * @param $node * A node array or node object. * @param $teaser * Whether to display the teaser only or the full form. - * @param $links - * Whether or not to display node links. Links are omitted for node previews. * * @return - * An HTML representation of the themed node. + * An array as expected by drupal_render(). */ function node_view($node, $teaser = FALSE) { $node = (object)$node; $node = node_build_content($node, $teaser); - - return theme('node', $node, $teaser); + + $render = $node->content; + $render += array( + '#theme' => 'node', + 'node' => $node, + 'teaser' => $teaser, + ); + return $render; } /** @@ -1208,19 +1212,17 @@ function node_build_content($node, $teas } /** - * Generate a page displaying a single node. + * Generate an array which displays a single node. */ function node_show($node, $message = FALSE) { if ($message) { drupal_set_title(t('Revision of %title from %date', array('%title' => $node->title, '%date' => format_date($node->revision_timestamp))), PASS_THROUGH); } - $output = node_view($node, FALSE, TRUE); - // Update the history table, stating that this user viewed this node. node_tag_new($node->nid); - return $output; + return node_view($node, FALSE); } /** @@ -1872,20 +1874,42 @@ function node_feed($nids = FALSE, $chann } /** + * Construct a drupal_render() style array from an array of loaded nodes. + * + * @param array $nodes + * An array of nodes as returned by node_load_multiple(). + * @param boolean $teaser + * Display nodes into teaser view or full view. + * @param integer $weight + * An integer representing the weight of the first node in the list. + * @return + * An array in the format expected by drupal_render(). + */ +function node_build_multiple($nodes, $teaser = TRUE, $weight = 0) { + $render = array(); + foreach ($nodes as $node) { + $render["nid_$node->nid"] = node_view($node, $teaser); + $render["nid_$node->nid"]['#weight'] = $weight; + $weight++; + } + return $render; +} + +/** * Menu callback; Generate a listing of promoted nodes. */ function node_page_default() { $nids = pager_query(db_rewrite_sql('SELECT n.nid 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))->fetchCol(); if (!empty($nids)) { $nodes = node_load_multiple($nids); - $output = ''; - foreach ($nodes as $node) { - $output .= node_view($node, TRUE); - } + $page = node_build_multiple($nodes); $feed_url = url('rss.xml', array('absolute' => TRUE)); drupal_add_feed($feed_url, variable_get('site_name', 'Drupal') . ' ' . t('RSS')); - $output .= theme('pager', NULL, variable_get('default_nodes_main', 10)); + $page['pager'] = array( + '#markup' => theme('pager', NULL, variable_get('default_nodes_main', 10)), + '#weight' => count($nodes), + ); } else { $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 = '' . t('There are currently no posts in this category.') . '
'; - } - return $output; + return $nids; } /** Index: modules/taxonomy/taxonomy.pages.inc =================================================================== RCS file: /cvs/drupal/drupal/modules/taxonomy/taxonomy.pages.inc,v retrieving revision 1.19 diff -u -F^f -p -r1.19 taxonomy.pages.inc --- modules/taxonomy/taxonomy.pages.inc 19 Dec 2008 03:55:23 -0000 1.19 +++ modules/taxonomy/taxonomy.pages.inc 2 Jan 2009 14:11:00 -0000 @@ -42,12 +42,37 @@ function taxonomy_term_page($terms, $dep $breadcrumb[] = l(t('Home'), NULL); $breadcrumb = array_reverse($breadcrumb); drupal_set_breadcrumb($breadcrumb); - - $output = theme('taxonomy_term_page', $tids, taxonomy_select_nodes($tids, $terms['operator'], $depth, TRUE)); drupal_add_feed(url('taxonomy/term/' . $str_tids . '/' . $depth . '/feed'), 'RSS - ' . $title); - return $output; + + if ($nids = taxonomy_select_nodes($tids, $terms['operator'], $depth, TRUE)) { + drupal_add_css(drupal_get_path('module', 'taxonomy') . '/taxonomy.css'); + $page = array(); + + // Only display the description if we have a single term, to avoid clutter and confusion. + if (count($tids) == 1) { + $term = taxonomy_term_load($tids[0]); + $description = $term->description; + + // Check that a description is set. + if (!empty($description)) { + $page['term_description'] = array( + '#markup' => filter_xss_admin($description), + '#weight' => -1, + '#prefix' => '