diff --git a/modules/node.module b/modules/node.module
index bdce5ebea327aeac23282c4e9a3f980d045e6786..092523f1b30a5cb4a8af0eb2a9e321e646b6f775 100644
--- a/modules/node.module
+++ b/modules/node.module
@@ -731,94 +731,6 @@ function node_search($op = 'search', $keys = null) {
                            'snippet' => search_excerpt($keys, $node->body));
       }
       return $results;
-
-    case 'form':
-      $form = array();
-
-      // Keyword boxes
-      $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,
-      );
-
-      // Taxonomy box
-      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,
-        );
-      }
-
-      // Node types
-      $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 clear="all" />',
-      );
-      return $form;
-
-    case 'post':
-      // Insert extra restrictions into the search keywords string.
-      $edit = &$_POST['edit'];
-      if (isset($edit['type']) && is_array($edit['type'])) {
-        $keys = search_query_insert($keys, 'type', implode(',', array_keys($edit['type'])));
-      }
-      if (isset($edit['category']) && is_array($edit['category'])) {
-        $keys = search_query_insert($keys, 'category', implode(',', $edit['category']));
-      }
-      if ($edit['or'] != '') {
-        if (preg_match_all('/ ("[^"]+"|[^" ]+)/i', ' '. $edit['or'], $matches)) {
-          $keys = $keys .' '. implode(' OR ', $matches[1]);
-        }
-      }
-      if ($edit['negative'] != '') {
-        if (preg_match_all('/ ("[^"]+"|[^" ]+)/i', ' '. $edit['negative'], $matches)) {
-          $keys = $keys .' -'. implode(' -', $matches[1]);
-        }
-      }
-      if ($edit['phrase'] != '') {
-        $keys .= ' "'. str_replace('"', ' ', $edit['phrase']) .'"';
-      }
-      return trim($keys);
   }
 }
 
@@ -2163,14 +2075,126 @@ function node_update_index() {
   }
 }
 
+/**
+ * Implementation of hook_form_alter().
+ */
 function node_form_alter($form_id, &$form) {
+  // Node publishing options
   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')),
+    $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.'),
     );
   }
+
+  // Advanced node search form
+  elseif ($form_id == 'search_form' && arg(1) == 'node') {
+    // Keyword boxes:
+    $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,
+    );
+
+    // Taxonomy box:
+    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,
+      );
+    }
+
+    // Node types:
+    $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 clear="all" />',
+    );
+
+    $form['#validate']['node_search_validate'] = array();
+  }
+}
+
+/**
+ * Form API callback for the search form. Registered in node_form_alter().
+ */
+function node_search_validate($form_id, $form_values) {
+  // Initialise using any existing basic search keywords.
+  $keys = $form_values['processed_keys']['#ref'];
+
+  // Insert extra restrictions into the search keywords string.
+  if (isset($form_values['type']) && is_array($form_values['type'])) {
+    // Retrieve selected types - Forms API sets the value of unselected checkboxes to 0.
+    $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_values['processed_keys']['#ref'] = trim($keys);
+  }
 }
 
 /**
diff --git a/modules/node/node.module b/modules/node/node.module
index bdce5ebea327aeac23282c4e9a3f980d045e6786..092523f1b30a5cb4a8af0eb2a9e321e646b6f775 100644
--- a/modules/node/node.module
+++ b/modules/node/node.module
@@ -731,94 +731,6 @@ function node_search($op = 'search', $keys = null) {
                            'snippet' => search_excerpt($keys, $node->body));
       }
       return $results;
-
-    case 'form':
-      $form = array();
-
-      // Keyword boxes
-      $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,
-      );
-
-      // Taxonomy box
-      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,
-        );
-      }
-
-      // Node types
-      $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 clear="all" />',
-      );
-      return $form;
-
-    case 'post':
-      // Insert extra restrictions into the search keywords string.
-      $edit = &$_POST['edit'];
-      if (isset($edit['type']) && is_array($edit['type'])) {
-        $keys = search_query_insert($keys, 'type', implode(',', array_keys($edit['type'])));
-      }
-      if (isset($edit['category']) && is_array($edit['category'])) {
-        $keys = search_query_insert($keys, 'category', implode(',', $edit['category']));
-      }
-      if ($edit['or'] != '') {
-        if (preg_match_all('/ ("[^"]+"|[^" ]+)/i', ' '. $edit['or'], $matches)) {
-          $keys = $keys .' '. implode(' OR ', $matches[1]);
-        }
-      }
-      if ($edit['negative'] != '') {
-        if (preg_match_all('/ ("[^"]+"|[^" ]+)/i', ' '. $edit['negative'], $matches)) {
-          $keys = $keys .' -'. implode(' -', $matches[1]);
-        }
-      }
-      if ($edit['phrase'] != '') {
-        $keys .= ' "'. str_replace('"', ' ', $edit['phrase']) .'"';
-      }
-      return trim($keys);
   }
 }
 
@@ -2163,14 +2075,126 @@ function node_update_index() {
   }
 }
 
+/**
+ * Implementation of hook_form_alter().
+ */
 function node_form_alter($form_id, &$form) {
+  // Node publishing options
   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')),
+    $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.'),
     );
   }
+
+  // Advanced node search form
+  elseif ($form_id == 'search_form' && arg(1) == 'node') {
+    // Keyword boxes:
+    $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,
+    );
+
+    // Taxonomy box:
+    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,
+      );
+    }
+
+    // Node types:
+    $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 clear="all" />',
+    );
+
+    $form['#validate']['node_search_validate'] = array();
+  }
+}
+
+/**
+ * Form API callback for the search form. Registered in node_form_alter().
+ */
+function node_search_validate($form_id, $form_values) {
+  // Initialise using any existing basic search keywords.
+  $keys = $form_values['processed_keys']['#ref'];
+
+  // Insert extra restrictions into the search keywords string.
+  if (isset($form_values['type']) && is_array($form_values['type'])) {
+    // Retrieve selected types - Forms API sets the value of unselected checkboxes to 0.
+    $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_values['processed_keys']['#ref'] = trim($keys);
+  }
 }
 
 /**
diff --git a/modules/search.module b/modules/search.module
index 9353e1028e7db62b0ecd57353bd620b0f4930eb9..e2999c42d930f1dfd43e8874d82625b547078ba6 100644
--- a/modules/search.module
+++ b/modules/search.module
@@ -890,30 +890,19 @@ function search_view() {
   // Search form submits with POST but redirects to GET. This way we can keep
   // the search query URL clean as a whistle:
   // search/type/keyword+keyword
-  if (isset($_POST['edit']['keys'])) {
+  if (!isset($_POST['edit']['keys'])) {
     if ($type == '') {
-      $type = 'node';
+      // Note: search/node can not be a default tab because it would take on the
+      // path of its parent (search). It would prevent remembering keywords when
+      // switching tabs. This is why we drupal_goto to it from the parent instead.
+      drupal_goto('search/node');
     }
-    $keys = module_invoke($type, 'search', 'post', $_POST['edit']['keys']);
-    drupal_goto('search/'. $type .'/'. (is_null($keys) ? $_POST['edit']['keys'] : $keys));
-  }
-  else if ($type == '') {
-    // Note: search/node can not be a default tab because it would take on the
-    // path of its parent (search). It would prevent remembering keywords when
-    // switching tabs. This is why we drupal_goto to it from the parent instead.
-    drupal_goto('search/node');
-  }
-  $keys = search_get_keys();
 
-  if (user_access('search content')) {
+    $keys = search_get_keys();
     // Only perform search if there is non-whitespace search term:
     if (trim($keys)) {
       // Log the search keys:
-      watchdog('search',
-        t('Search: %keys (%type).', array('%keys' => theme('placeholder', $keys), '%type' => module_invoke($type, 'search', 'name'))),
-        WATCHDOG_NOTICE,
-        l(t('results'), 'search/'. $type .'/'. $keys)
-        );
+      watchdog('search', t('Search: %keys (%type).', array('%keys' => theme('placeholder', $keys), '%type' => module_invoke($type, 'search', 'name'))), WATCHDOG_NOTICE, l(t('results'), 'search/'. $type .'/'. $keys));
 
       // Collect the search results:
       $results = search_data($keys, $type);
@@ -925,21 +914,15 @@ function search_view() {
         $results = theme('box', t('Your search yielded no results'), search_help('search#noresults'));
       }
     }
-    else if (isset($_POST['edit'])) {
-      form_set_error('keys', t('Please enter some keywords.'));
-    }
 
     // Construct the search form.
-    // Note, we do this last because of the form_set_error() above.
     $output = search_form(NULL, $keys, $type);
-
     $output .= $results;
 
     return $output;
   }
-  else {
-    drupal_access_denied();
-  }
+
+  return search_form(NULL, $keys, $type);
 }
 
 /**
@@ -985,7 +968,7 @@ function search_view() {
  * @return
  *   An HTML string containing the search form.
  */
-function search_form($action = '', $keys = '', $type = null, $prompt = null) {
+function search_form($action = '', $keys = '', $type = NULL, $prompt = NULL) {
 
   if (!$action) {
     $action = url('search/'. $type);
@@ -994,18 +977,51 @@ function search_form($action = '', $keys = '', $type = null, $prompt = null) {
     $prompt = t('Enter your keywords');
   }
 
-  $form = array('#action' => $action, '#attributes' => array('class' => 'search-form'), '#redirect' => FALSE);
+  $form = array(
+    '#action' => $action,
+    '#attributes' => array('class' => 'search-form'),
+    '#redirect' => FALSE,
+  );
+  $form['module'] = array('#type' => 'value', '#value' => $type);
   $form['basic'] = array('#type' => 'item', '#title' => $prompt);
-  $form['basic']['inline'] = array('#type' => 'markup', '#prefix' => '<div class="container-inline">', '#suffix' => '</div>');
-  $form['basic']['inline']['keys'] = array('#type' => 'textfield', '#title' => '', '#default_value' => $keys, '#size' => $prompt ? 40 : 20, '#maxlength' => 255);
+  $form['basic']['inline'] = array('#prefix' => '<div class="container-inline">', '#suffix' => '</div>');
+  $form['basic']['inline']['keys'] = array(
+    '#type' => 'textfield',
+    '#title' => '',
+    '#default_value' => $keys,
+    '#size' => $prompt ? 40 : 20,
+    '#maxlength' => 255,
+  );
+  // processed_keys is used to coordinate keyword passing between other forms that hook into the basic search form.
+  $form['basic']['inline']['processed_keys'] = array('#type' => 'value', '#value' => array());
   $form['basic']['inline']['submit'] = array('#type' => 'submit', '#value' => t('Search'));
 
-  $form_module = module_invoke($type, 'search', 'form', $keys);
-  if (isset($form_module) && is_array($form_module)) {
-    $form = array_merge($form, $form_module);
+  return drupal_get_form('search_form', $form);
+}
+
+/**
+ * As the search form collates keys from other modules hooked in via hook_form_alter, the validation 
+ * takes place in _submit. search_form_validate() is used solely to set the #ref property for the basic 
+ * search form.
+ */
+function search_form_validate($form_id, $form_values) {
+  $form_values['processed_keys']['#ref'] = trim($form_values['keys']);
+}
+
+/**
+ * Process a search form submission. Uses a forms API #ref to accept processed search keys
+ * from forms that hook into the default search form.
+ */
+function search_form_submit($form_id, $form_values) {
+  $keys = $form_values['processed_keys']['#ref'];
+  if (trim($keys) == '') {
+    form_set_error('keys', t('Please enter some keywords.'));
+    // Fall through to the drupal_goto() call.
+    $keys = '';
   }
 
-  return drupal_get_form('search_form', $form);
+  $type = $form_values['module'] ? $form_values['module'] : 'node';
+  drupal_goto('search/'. $type .'/'. $keys);
 }
 
 /**
diff --git a/modules/search/search.module b/modules/search/search.module
index 9353e1028e7db62b0ecd57353bd620b0f4930eb9..e2999c42d930f1dfd43e8874d82625b547078ba6 100644
--- a/modules/search/search.module
+++ b/modules/search/search.module
@@ -890,30 +890,19 @@ function search_view() {
   // Search form submits with POST but redirects to GET. This way we can keep
   // the search query URL clean as a whistle:
   // search/type/keyword+keyword
-  if (isset($_POST['edit']['keys'])) {
+  if (!isset($_POST['edit']['keys'])) {
     if ($type == '') {
-      $type = 'node';
+      // Note: search/node can not be a default tab because it would take on the
+      // path of its parent (search). It would prevent remembering keywords when
+      // switching tabs. This is why we drupal_goto to it from the parent instead.
+      drupal_goto('search/node');
     }
-    $keys = module_invoke($type, 'search', 'post', $_POST['edit']['keys']);
-    drupal_goto('search/'. $type .'/'. (is_null($keys) ? $_POST['edit']['keys'] : $keys));
-  }
-  else if ($type == '') {
-    // Note: search/node can not be a default tab because it would take on the
-    // path of its parent (search). It would prevent remembering keywords when
-    // switching tabs. This is why we drupal_goto to it from the parent instead.
-    drupal_goto('search/node');
-  }
-  $keys = search_get_keys();
 
-  if (user_access('search content')) {
+    $keys = search_get_keys();
     // Only perform search if there is non-whitespace search term:
     if (trim($keys)) {
       // Log the search keys:
-      watchdog('search',
-        t('Search: %keys (%type).', array('%keys' => theme('placeholder', $keys), '%type' => module_invoke($type, 'search', 'name'))),
-        WATCHDOG_NOTICE,
-        l(t('results'), 'search/'. $type .'/'. $keys)
-        );
+      watchdog('search', t('Search: %keys (%type).', array('%keys' => theme('placeholder', $keys), '%type' => module_invoke($type, 'search', 'name'))), WATCHDOG_NOTICE, l(t('results'), 'search/'. $type .'/'. $keys));
 
       // Collect the search results:
       $results = search_data($keys, $type);
@@ -925,21 +914,15 @@ function search_view() {
         $results = theme('box', t('Your search yielded no results'), search_help('search#noresults'));
       }
     }
-    else if (isset($_POST['edit'])) {
-      form_set_error('keys', t('Please enter some keywords.'));
-    }
 
     // Construct the search form.
-    // Note, we do this last because of the form_set_error() above.
     $output = search_form(NULL, $keys, $type);
-
     $output .= $results;
 
     return $output;
   }
-  else {
-    drupal_access_denied();
-  }
+
+  return search_form(NULL, $keys, $type);
 }
 
 /**
@@ -985,7 +968,7 @@ function search_view() {
  * @return
  *   An HTML string containing the search form.
  */
-function search_form($action = '', $keys = '', $type = null, $prompt = null) {
+function search_form($action = '', $keys = '', $type = NULL, $prompt = NULL) {
 
   if (!$action) {
     $action = url('search/'. $type);
@@ -994,18 +977,51 @@ function search_form($action = '', $keys = '', $type = null, $prompt = null) {
     $prompt = t('Enter your keywords');
   }
 
-  $form = array('#action' => $action, '#attributes' => array('class' => 'search-form'), '#redirect' => FALSE);
+  $form = array(
+    '#action' => $action,
+    '#attributes' => array('class' => 'search-form'),
+    '#redirect' => FALSE,
+  );
+  $form['module'] = array('#type' => 'value', '#value' => $type);
   $form['basic'] = array('#type' => 'item', '#title' => $prompt);
-  $form['basic']['inline'] = array('#type' => 'markup', '#prefix' => '<div class="container-inline">', '#suffix' => '</div>');
-  $form['basic']['inline']['keys'] = array('#type' => 'textfield', '#title' => '', '#default_value' => $keys, '#size' => $prompt ? 40 : 20, '#maxlength' => 255);
+  $form['basic']['inline'] = array('#prefix' => '<div class="container-inline">', '#suffix' => '</div>');
+  $form['basic']['inline']['keys'] = array(
+    '#type' => 'textfield',
+    '#title' => '',
+    '#default_value' => $keys,
+    '#size' => $prompt ? 40 : 20,
+    '#maxlength' => 255,
+  );
+  // processed_keys is used to coordinate keyword passing between other forms that hook into the basic search form.
+  $form['basic']['inline']['processed_keys'] = array('#type' => 'value', '#value' => array());
   $form['basic']['inline']['submit'] = array('#type' => 'submit', '#value' => t('Search'));
 
-  $form_module = module_invoke($type, 'search', 'form', $keys);
-  if (isset($form_module) && is_array($form_module)) {
-    $form = array_merge($form, $form_module);
+  return drupal_get_form('search_form', $form);
+}
+
+/**
+ * As the search form collates keys from other modules hooked in via hook_form_alter, the validation 
+ * takes place in _submit. search_form_validate() is used solely to set the #ref property for the basic 
+ * search form.
+ */
+function search_form_validate($form_id, $form_values) {
+  $form_values['processed_keys']['#ref'] = trim($form_values['keys']);
+}
+
+/**
+ * Process a search form submission. Uses a forms API #ref to accept processed search keys
+ * from forms that hook into the default search form.
+ */
+function search_form_submit($form_id, $form_values) {
+  $keys = $form_values['processed_keys']['#ref'];
+  if (trim($keys) == '') {
+    form_set_error('keys', t('Please enter some keywords.'));
+    // Fall through to the drupal_goto() call.
+    $keys = '';
   }
 
-  return drupal_get_form('search_form', $form);
+  $type = $form_values['module'] ? $form_values['module'] : 'node';
+  drupal_goto('search/'. $type .'/'. $keys);
 }
 
 /**