diff --git modules/search/search.api.php modules/search/search.api.php
index a2dd95f..ed4bd17 100644
--- modules/search/search.api.php
+++ modules/search/search.api.php
@@ -25,9 +25,11 @@
  * hook_update_index(). If your search type has settings, you can implement
  * hook_search_admin() to add them to the search settings page. You can also
  * alter the display of your module's search results by implementing
- * hook_search_page(). And you can use hook_form_FORM_ID_alter(), with
- * FORM_ID set to 'search', to add fields to the search form. See
- * node_form_search_form_alter() for an example.
+ * hook_search_page(). You can use hook_form_FORM_ID_alter(), with
+ * FORM_ID set to 'search', to add fields to the search form (see
+ * node_form_search_form_alter() for an example). You can use
+ * hook_search_access() to limit access to searching, and hook_search_page() to
+ * override how search results are displayed.
  *
  * @return
  *   Array with optional keys:
@@ -248,7 +250,7 @@ function hook_search_execute($keys = NULL, $conditions = NULL) {
 /**
  * Override the rendering of search results.
  *
- * A module that implements hook_search() to define a type of search
+ * A module that implements hook_search_info() to define a type of search
  * may implement this hook in order to override the default theming of
  * its search results, which is otherwise themed using theme('search_results').
  *
@@ -269,10 +271,10 @@ function hook_search_page($results) {
   $output = '<ol class="search-results">';
 
   foreach ($results as $entry) {
-    $output .= theme('search_result', $entry, $type);
+    $output .= theme('search_result', array('result' => $entry, 'type' => 'my_module_name'));
   }
   $output .= '</ol>';
-  $output .= theme('pager', NULL);
+  $output .= theme('pager');
 
   return $output;
 }
diff --git modules/search/search.module modules/search/search.module
index 2b114b1..c18f5ec 100644
--- modules/search/search.module
+++ modules/search/search.module
@@ -1041,17 +1041,23 @@ function template_preprocess_search_block_form(&$variables) {
  *   Optional array of additional search conditions.
  *
  * @return
- *   Formatted search results. No return value if $keys are not supplied or
- *   if the given search module is not active.
+ *   Renderable array of search results. No return value if $keys are not
+ *   supplied or if the given search module is not active.
  */
 function search_data($keys, $module, $conditions = NULL) {
   if (module_hook($module, 'search_execute')) {
     $results = module_invoke($module, 'search_execute', $keys, $conditions);
     if (module_hook($module, 'search_page')) {
-      return module_invoke($module, 'search_page', $results);
+      return array(
+        '#markup' => module_invoke($module, 'search_page', $results),
+      );
     }
     else {
-      return theme('search_results', array('results' => $results, 'type' => $module));
+      return array(
+        '#theme' => 'search_results',
+        '#results' => $results,
+        '#type' => $module,
+      );
     }
   }
 }
diff --git modules/search/search.pages.inc modules/search/search.pages.inc
index 984073a..4800698 100644
--- modules/search/search.pages.inc
+++ modules/search/search.pages.inc
@@ -44,7 +44,8 @@ function search_view($module = NULL, $keys = '') {
     drupal_goto($path);
   }
 
-  $results = '';
+  // Default results output is an empty string.
+  $results = array('#markup' => '');
   // Process the search form. Note that if there is $_POST data,
   // search_form_submit() will cause a redirect to search/[module path]/[keys],
   // which will get us back to this page callback. In other words, the search
@@ -67,7 +68,7 @@ function search_view($module = NULL, $keys = '') {
   }
   // The form may be altered based on whether the search was run.
   $build['search_form'] = drupal_get_form('search_form', NULL, $keys, $info['module']);
-  $build['search_results'] = array('#markup' => $results);
+  $build['search_results'] = $results;
 
   return $build;
 }
diff --git modules/search/search.test modules/search/search.test
index 2b5b4f7..587e9cd 100644
--- modules/search/search.test
+++ modules/search/search.test
@@ -990,7 +990,7 @@ class SearchSimplifyTestCase extends DrupalWebTestCase {
 
 
 /**
- * Test config page.
+ * Tests keywords and conditions.
  */
 class SearchKeywordsConditions extends DrupalWebTestCase {
 
@@ -1463,3 +1463,37 @@ class SearchEmbedForm extends DrupalWebTestCase {
     $this->submit_count = $count;
   }
 }
+
+/**
+ * Tests that hook_search_page runs.
+ */
+class SearchPageOverride extends DrupalWebTestCase {
+  public $search_user;
+
+  public static function getInfo() {
+    return array(
+      'name' => 'Search page override',
+      'description' => 'Verify that hook_search_page can override search page display.',
+      'group' => 'Search',
+    );
+  }
+
+  function setUp() {
+    parent::setUp('search', 'search_extra_type');
+
+    // Login as a user that can create and search content.
+    $this->search_user = $this->drupalCreateUser(array('search content', 'administer search'));
+    $this->drupalLogin($this->search_user);
+
+    // Enable the extra type module for searching.
+    variable_set('search_active_modules', array('node' => 'node', 'user' => 'user', 'search_extra_type' => 'search_extra_type'));
+    menu_rebuild();
+  }
+
+  function testSearchPageHook() {
+    $keys = 'bike shed ' . $this->randomName();
+    $this->drupalGet("search/dummy_path/{$keys}");
+    $this->assertText('Dummy search snippet', 'Dummy search snippet is shown');
+    $this->assertText('Test page text is here', 'Page override is working');
+  }
+}
diff --git modules/search/tests/search_extra_type.module modules/search/tests/search_extra_type.module
index fcb8a39..36180e5 100644
--- modules/search/tests/search_extra_type.module
+++ modules/search/tests/search_extra_type.module
@@ -17,6 +17,9 @@ function search_extra_type_search_info() {
   );
 }
 
+/**
+ * Test conditions callback for hook_search_info().
+ */
 function search_extra_type_conditions() {
   $conditions = array();
 
@@ -45,3 +48,21 @@ function search_extra_type_search_execute($keys = NULL, $conditions = NULL) {
     ),
   );
 }
+
+/**
+ * Implements hook_search_page().
+ *
+ * Adds some text to the search page so we can verify that it runs.
+ */
+function search_extra_type_search_page($results) {
+  $output = '<h2>Test page text is here</h2>';
+  $output .= '<ol class="search-results">';
+
+  foreach ($results as $entry) {
+    $output .= theme('search_result', array('result' => $entry, 'type' => 'search_extra_type'));
+  }
+  $output .= '</ol>';
+  $output .= theme('pager');
+
+  return $output;
+}
