diff --git includes/common.inc includes/common.inc
index 58b0845..2f6be3d 100644
--- includes/common.inc
+++ includes/common.inc
@@ -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,
+    '#page_properties' => array('#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,
+    '#page_properties' => array('#show_blocks' => FALSE),
+  ));
 }
 
 /**
@@ -821,7 +828,11 @@ function _drupal_log_error($error, $fatal = FALSE) {
     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.'),
+        '#page_properties' => array('#show_blocks' => FALSE),
+      ));
     }
     else {
       print theme('maintenance_page', t('The website encountered an unexpected error. Please try again later.'), FALSE);
@@ -3176,6 +3187,66 @@ 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) {
+  $page['#type'] = 'page';
+  // Merge in default values.
+  $page = array_merge($page, _element_info('page'));
+  // Merge in properties passed by the caller.
+  if (isset($content['#page_properties']) && is_array($content['#page_properties'])) {
+    $page = array_merge($page, $content['#page_properties']);
+  }
+  // Set the main content.
+  if (is_array($content)) {
+    $page['content'] = $content;
+  }
+  else {
+    $page['content'] = array('#markup' => $content);
+  }
+  
+  // Load the blocks and merge the regions into the page array.
+  $regions = drupal_get_blocks($page['#show_blocks']);
+  foreach ($regions as $region => $blocks) {
+    $page[$region]['blocks'] = array('#markup' => $blocks);
+  }
+  drupal_alter('page', $page);
+  print drupal_render($page);
+}
+
+/**
+ * Get all rendered blocks for the current page, keyed by region.
+ *
+ * @param $show_blocks
+ *   If FALSE, the left and right regions are prevented from rendering blocks.
+ */
+function drupal_get_blocks($show_blocks = TRUE) {
+  // The theme system might not yet be initialized.
+  init_theme();
+  global $theme;
+  
+  $output = array();
+  // Populate all block regions.
+  $regions = system_region_list($theme);
+  // Load all region content assigned via blocks.
+  foreach (array_keys($regions) as $region) {
+    // Prevent left and right regions from rendering blocks when 'show_blocks' == FALSE.
+    if ($show_blocks || ($region != 'left' && $region != 'right')) {
+      $blocks = theme('blocks', $region);
+    }
+    else {
+      $blocks = '';
+    }
+    // Assign region to a region variable.
+    $output[$region] = $blocks;
+  }
+  return $output;
+}
+
+/**
  * Renders HTML given a structured array tree.
  *
  * Recursively iterates over each of the array elements, generating HTML code.
@@ -3246,7 +3317,17 @@ function drupal_render(&$elements) {
     // Render each of the children using drupal_render and concatenate them.
     if (!isset($content) || $content === '') {
       foreach ($children as $key) {
-        $content .= drupal_render($elements[$key]);
+        // If #concatenate_children is set to FALSE, the rendered children of the
+        // element are not concatenated into a single string, but instead kept as
+        // a keyed array of rendered string in the #children property of the parent
+        // element. The parent's element theming function is then responsible for
+        // printing out all elements in the #children array.
+        if (isset($elements['#concatenate_children']) && $elements['#concatenate_children'] == FALSE) {
+          $content[$key] = drupal_render($elements[$key]);
+        }
+        else {
+          $content .= drupal_render($elements[$key]);
+        }
       }
     }
   }
@@ -3339,7 +3420,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 +3479,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),
     ),
diff --git includes/theme.inc includes/theme.inc
index 37d8652..9897a45 100644
--- includes/theme.inc
+++ includes/theme.inc
@@ -1571,6 +1571,28 @@ function theme_item_list($items = array(), $title = NULL, $type = 'ul', $attribu
 }
 
 /**
+ * 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,27 +1847,23 @@ function template_preprocess(&$variables, $hook) {
  * @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', 'show_messages');
+  foreach ($names as $name) {
+    $variables[$name] = $variables['content']['#'. $name];
+  }
+  
+  // Import children of the content array as variables.
+  // This contains the main 'content' and the regions (with rendered blocks).
+  $content = $variables['content']['#children'];
+  foreach ($content as $key => $child) {
+    $variables[$key] = $child;
+  }
   // Add favicon
   if (theme_get_setting('toggle_favicon')) {
     drupal_set_html_head('<link rel="shortcut icon" href="' . check_url(theme_get_setting('favicon')) . '" type="image/x-icon" />');
   }
 
-  global $theme;
-  // Populate all block regions.
-  $regions = system_region_list($theme);
-  // Load all region content assigned via blocks.
-  foreach (array_keys($regions) as $region) {
-    // Prevent left and right regions from rendering blocks when 'show_blocks' == FALSE.
-    if ($variables['show_blocks'] || ($region != 'left' && $region != 'right')) {
-      $blocks = theme('blocks', $region);
-    }
-    else {
-      $blocks = '';
-    }
-    // Assign region to a region variable.
-    isset($variables[$region]) ? $variables[$region] .= $blocks : $variables[$region] = $blocks;
-  }
-
   // Set up layout variable.
   $variables['layout'] = 'none';
   if (!empty($variables['left'])) {
@@ -1977,6 +1995,8 @@ function template_preprocess_page(&$variables) {
  * @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);
diff --git index.php index.php
index e9cdef1..0eeb3aa 100644
--- index.php
+++ index.php
@@ -21,7 +21,7 @@ require_once DRUPAL_ROOT . '/includes/bootstrap.inc';
 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();
diff --git modules/blog/blog.pages.inc modules/blog/blog.pages.inc
index a48c432..4308ae5 100644
--- modules/blog/blog.pages.inc
+++ modules/blog/blog.pages.inc
@@ -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");
+    $page['blog_actions'] = array(
+      '#items' => $items,
+      '#theme' => 'list',
+      '#weight' => -1,
+    );
   }
 
-  $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;
-  }
+  $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 ($has_posts) {
-    $output .= theme('pager', NULL, variable_get('default_nodes_main', 10));
+  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;
 }
 
 /**
diff --git modules/comment/comment.module modules/comment/comment.module
index 58e8315..f196ee4 100644
--- modules/comment/comment.module
+++ modules/comment/comment.module
@@ -1628,7 +1628,7 @@ function comment_form_add_preview($form, &$form_state) {
   }
   else {
     $suffix = empty($form['#suffix']) ? '' : $form['#suffix'];
-    $form['#suffix'] = $suffix . node_view($node);
+    $form['#suffix'] = $suffix . drupal_render(node_view($node));
     $edit['pid'] = 0;
   }
 
diff --git modules/comment/comment.pages.inc modules/comment/comment.pages.inc
index d36d04f..a656835 100644
--- modules/comment/comment.pages.inc
+++ modules/comment/comment.pages.inc
@@ -92,7 +92,7 @@ function comment_reply($node, $pid = NULL) {
       }
       // 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?
diff --git modules/node/node.api.php modules/node/node.api.php
index 4a8636a..75937df 100644
--- modules/node/node.api.php
+++ modules/node/node.api.php
@@ -169,7 +169,7 @@ function hook_node_operations() {
  * @return
  *   None.
  */
-function hook_nodeapi_alter($node, $teaser, $page) {
+function hook_nodeapi_alter($node, $teaser) {
 }
 
 /**
diff --git modules/node/node.module modules/node/node.module
index d2d3771..8cec3c7 100644
--- modules/node/node.module
+++ modules/node/node.module
@@ -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, $teaser = FALSE) {
 }
 
 /**
- * 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, $channel = array()) {
 }
 
 /**
+ * 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 = '<h1 class="title">' . t('Welcome to your new Drupal website!') . '</h1>';
@@ -1898,11 +1922,11 @@ function node_page_default() {
     $default_message .= '</ol>';
     $default_message .= '<p>' . t('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.', array('@help' => url('admin/help'), '@handbook' => 'http://drupal.org/handbooks', '@forum' => 'http://drupal.org/forum', '@support' => 'http://drupal.org/support')) . '</p>';
 
-    $output = '<div id="first-time">' . $default_message . '</div>';
+    $page = array('#markup' => '<div id="first-time">' . $default_message . '</div>');
   }
   drupal_set_title('');
 
-  return $output;
+  return $page;
 }
 
 /**
@@ -2930,7 +2954,7 @@ function node_unpublish_by_keyword_action_submit($form, $form_state) {
  */
 function node_unpublish_by_keyword_action($node, $context) {
   foreach ($context['keywords'] as $keyword) {
-    if (strstr(node_view(clone $node), $keyword) || strstr($node->title, $keyword)) {
+    if (strstr(drupal_render(node_view(clone $node)), $keyword) || strstr($node->title, $keyword)) {
       $node->status = 0;
       watchdog('action', 'Set @type %title to unpublished.', array('@type' => node_get_types('name', $node), '%title' => $node->title));
       break;
diff --git modules/node/node.pages.inc modules/node/node.pages.inc
index 76e28b1..511c042 100644
--- modules/node/node.pages.inc
+++ modules/node/node.pages.inc
@@ -415,12 +415,12 @@ function theme_node_preview($node) {
   if ($preview_trimmed_version) {
     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.<span class="no-js"> You can insert the delimiter "&lt;!--break--&gt;" (without the quotes) to fine-tune where your post gets split.</span>'));
     $output .= '<h3>' . t('Preview trimmed version') . '</h3>';
-    $output .= node_view(clone $node, 1, FALSE);
+    $output .= drupal_render(node_view(clone $node, TRUE));
     $output .= '<h3>' . t('Preview full version') . '</h3>';
-    $output .= node_view($node, 0, FALSE);
+    $output .= drupal_render(node_view($node, FALSE));
   }
   else {
-    $output .= node_view($node, 0, FALSE);
+    $output .= drupal_render(node_view($node, FALSE));
   }
   $output .= "</div>\n";
 
diff --git modules/system/system.admin.inc modules/system/system.admin.inc
index e3cc5bc..382091f 100644
--- modules/system/system.admin.inc
+++ modules/system/system.admin.inc
@@ -1900,7 +1900,7 @@ function system_batch_page() {
   elseif (isset($output)) {
     // Force a page without blocks or messages to
     // display a list of collected messages later.
-    print theme('page', $output, FALSE, FALSE);
+    return $output;
   }
 }
 
diff --git modules/system/system.api.php modules/system/system.api.php
index 278dca9..3e9bc22 100644
--- modules/system/system.api.php
+++ modules/system/system.api.php
@@ -180,6 +180,28 @@ function hook_js_alter(&$javascript) {
 }
 
 /**
+ * Perform alterations before a page is rendered.
+ *
+ * Use this hook when you want to add/remove elements at the page level. If are 
+ * making changes to forms or nodes or users, use their hook_OBJECT_alter() hook instead.
+ *
+ * @param $page
+ *   Nested array of render elements that comprise the page.
+ * @return
+ *   None.
+ */
+function hook_page_alter($page) {
+  if (menu_get_object()) {
+    // We are on a node detail page. Append a standard disclaimer.
+    $page['disclaimer'] = array(
+      '#markup' => t('Opinions expressed on this belong to the author, and not to Acme, Inc.'),
+      '#weight' => 25,
+    );
+  }
+}
+
+
+/**
  * Perform alterations before a form is rendered.
  *
  * One popular use of this hook is to add form elements to the node form. When
diff --git modules/system/system.module modules/system/system.module
index 4261399..6aed00e 100644
--- modules/system/system.module
+++ modules/system/system.module
@@ -236,6 +236,14 @@ function system_elements() {
     '#method' => 'post',
     '#action' => request_uri(),
   );
+  
+  // @see drupal_render_page().
+  $type['page'] = array(
+    '#show_messages' => TRUE,
+    '#show_blocks' => TRUE,
+    '#value' => NULL,
+    '#concatenate_children' => FALSE,
+  );
 
   /**
    * Input elements.
diff --git modules/taxonomy/taxonomy.module modules/taxonomy/taxonomy.module
index 5d4a468..32c5f49 100644
--- modules/taxonomy/taxonomy.module
+++ modules/taxonomy/taxonomy.module
@@ -26,9 +26,6 @@ function taxonomy_theme() {
     'taxonomy_term_select' => array(
       'arguments' => array('element' => NULL),
     ),
-    'taxonomy_term_page' => array(
-      'arguments' => array('tids' => array(), 'result' => NULL),
-    ),
     'taxonomy_overview_vocabularies' => array(
       'arguments' => array('form' => array()),
     ),
@@ -1223,7 +1220,7 @@ function theme_taxonomy_term_select($element) {
  * @param $order
  *   The order clause for the query that retrieve the nodes.
  * @return
- *   A resource identifier pointing to the query results.
+ *   An array node IDs.
  */
 function taxonomy_select_nodes($tids = array(), $operator = 'or', $depth = 0, $pager = TRUE, $order = 'n.sticky DESC, n.created DESC') {
   if (count($tids) > 0) {
@@ -1241,7 +1238,7 @@ function taxonomy_select_nodes($tids = array(), $operator = 'or', $depth = 0, $p
     if ($operator == 'or') {
       $args = call_user_func_array('array_merge', $descendant_tids);
       $placeholders = db_placeholders($args, 'int');
-      $sql = 'SELECT DISTINCT(n.nid), n.sticky, n.title, n.created FROM {node} n INNER JOIN {term_node} tn ON n.vid = tn.vid WHERE tn.tid IN (' . $placeholders . ') AND n.status = 1 ORDER BY ' . $order;
+      $sql = 'SELECT DISTINCT(n.nid) FROM {node} n INNER JOIN {term_node} tn ON n.vid = tn.vid WHERE tn.tid IN (' . $placeholders . ') AND n.status = 1 ORDER BY ' . $order;
       $sql_count = 'SELECT COUNT(DISTINCT(n.nid)) FROM {node} n INNER JOIN {term_node} tn ON n.vid = tn.vid WHERE tn.tid IN (' . $placeholders . ') AND n.status = 1';
     }
     else {
@@ -1253,44 +1250,20 @@ function taxonomy_select_nodes($tids = array(), $operator = 'or', $depth = 0, $p
         $wheres .= ' AND tn' . $index . '.tid IN (' . db_placeholders($tids, 'int') . ')';
         $args = array_merge($args, $tids);
       }
-      $sql = 'SELECT DISTINCT(n.nid), n.sticky, n.title, n.created FROM {node} n ' . $joins . ' WHERE n.status = 1 ' . $wheres . ' ORDER BY ' . $order;
+      $sql = 'SELECT DISTINCT(n.nid) FROM {node} n ' . $joins . ' WHERE n.status = 1 ' . $wheres . ' ORDER BY ' . $order;
       $sql_count = 'SELECT COUNT(DISTINCT(n.nid)) FROM {node} n ' . $joins . ' WHERE n.status = 1 ' . $wheres;
     }
     $sql = db_rewrite_sql($sql);
     $sql_count = db_rewrite_sql($sql_count);
     if ($pager) {
-      $result = pager_query($sql, variable_get('default_nodes_main', 10), 0, $sql_count, $args);
+      $nids = pager_query($sql, variable_get('default_nodes_main', 10), 0, $sql_count, $args)->fetchCol();
     }
     else {
-      $result = db_query_range($sql, $args, 0, variable_get('feed_default_items', 10));
+      $nids = db_query_range($sql, $args, 0, variable_get('feed_default_items', 10))->fetchCol();
     }
   }
 
-  return $result;
-}
-
-/**
- * Accepts the result of a pager_query() call, such as that performed by
- * taxonomy_select_nodes(), and formats each node along with a pager.
- */
-function taxonomy_render_nodes($result) {
-  $output = '';
-  $nids = array();
-  foreach ($result as $record) {
-    $nids[] = $record->nid;
-  }
-  if (!empty($nids)) {
-    $nodes = node_load_multiple($nids);
-
-    foreach ($nodes as $node) {
-      $output .= node_view($node, 1);
-    }
-    $output .= theme('pager', NULL, variable_get('default_nodes_main', 10), 0);
-  }
-  else {
-    $output .= '<p>' . t('There are currently no posts in this category.') . '</p>';
-  }
-  return $output;
+  return $nids;
 }
 
 /**
diff --git modules/taxonomy/taxonomy.pages.inc modules/taxonomy/taxonomy.pages.inc
index 1e448d0..0c5144e 100644
--- modules/taxonomy/taxonomy.pages.inc
+++ modules/taxonomy/taxonomy.pages.inc
@@ -42,12 +42,44 @@ function taxonomy_term_page($terms, $depth = 0, $op = 'page') {
           $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;
-          break;
+          
+          if ($nids = taxonomy_select_nodes($tids, $terms['operator'], $depth, TRUE)) {
+            drupal_add_css(drupal_get_path('module', 'taxonomy') . '/taxonomy.css');
+            $page = array();
+
+            $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 {
+            $page['no_posts'] = array(
+              '#prefix' => '<p>',
+              '#markup' => t('There are currently no posts in this category.'),
+              '#suffix' => '</p>',
+            );
+          }
 
+          // 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' => '<div class="taxonomy-term-description">',
+                '#suffix' => '</div>',
+              );
+            }
+          }
+          return $page;
+          break;
         case 'feed':
           $channel['link'] = url('taxonomy/term/' . $str_tids . '/' . $depth, array('absolute' => TRUE));
           $channel['title'] = variable_get('site_name', 'Drupal') . ' - ' . $title;
@@ -58,13 +90,9 @@ function taxonomy_term_page($terms, $depth = 0, $op = 'page') {
             $channel['description'] = $term->description;
           }
 
-          $result = taxonomy_select_nodes($tids, $terms['operator'], $depth, FALSE);
-          $items = array();
-          while ($row = db_fetch_object($result)) {
-            $items[] = $row->nid;
-          }
+          $nids = taxonomy_select_nodes($tids, $terms['operator'], $depth, FALSE);
 
-          node_feed($items, $channel);
+          node_feed($nids, $channel);
           break;
 
         default:
@@ -78,38 +106,6 @@ function taxonomy_term_page($terms, $depth = 0, $op = 'page') {
 }
 
 /**
- * Render a taxonomy term page HTML output.
- *
- * @param $tids
- *   An array of term ids.
- * @param $result
- *   A pager_query() result, such as that performed by taxonomy_select_nodes().
- *
- * @ingroup themeable
- */
-function theme_taxonomy_term_page($tids, $result) {
-  drupal_add_css(drupal_get_path('module', 'taxonomy') . '/taxonomy.css');
-  $output = '';
-
-  // 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)) {
-      $output .= '<div class="taxonomy-term-description">';
-      $output .= filter_xss_admin($description);
-      $output .= '</div>';
-    }
-  }
-
-  $output .= taxonomy_render_nodes($result);
-
-  return $output;
-}
-
-/**
  * Page to edit a vocabulary term.
  */
 function taxonomy_term_edit($term) {
diff --git modules/upload/upload.test modules/upload/upload.test
index 11c7e98..4cd4973 100644
--- modules/upload/upload.test
+++ modules/upload/upload.test
@@ -53,7 +53,7 @@ class UploadTestCase extends DrupalWebTestCase {
     
     // Assure that the attachment link appears on teaser view and has correct count.
     $node = node_load($node->nid);
-    $teaser = node_view($node, TRUE);
+    $teaser = drupal_render(node_view($node, TRUE));
     $this->assertTrue(strpos($teaser, format_plural(2, '1 attachment', '@count attachments')), 'Attachments link found on node teaser.');
 
     // Fetch db record and use fid to rename and delete file.
