diff --git a/core/modules/node/node.views.inc b/core/modules/node/node.views.inc
index 136628faa8d746ad672aa959a7fc6d544940445a..742ec5054f5cbeb9b694ad8b737997c1165c22da 100644
--- a/core/modules/node/node.views.inc
+++ b/core/modules/node/node.views.inc
@@ -619,6 +619,81 @@ function node_views_data() {
     ),
   );
 
+  // Add search table, fields, filters, etc., but only if a page using the
+  // node_search plugin is enabled.
+  if (\Drupal::moduleHandler()->moduleExists('search')) {
+    $enabled = FALSE;
+    $search_page_repository = \Drupal::service('search.search_page_repository');
+    foreach ($search_page_repository->getActiveSearchpages() as $page) {
+      if ($page->getPlugin()->getPluginId() == 'node_search') {
+        $enabled = TRUE;
+        break;
+      }
+    }
+
+    if ($enabled) {
+      $data['node_search_index']['table']['group'] = t('Search');
+
+      // Automatically join to the node table. Use a Views table alias to
+      // allow other modules to use this table too, if they use the search
+      // index.
+      $data['node_search_index']['table']['join'] = array(
+        'node' => array(
+          'left_field' => 'nid',
+          'field' => 'sid',
+          'table' => 'search_index',
+          'extra' => "node_search_index.type = 'node_search'",
+        )
+      );
+
+      $data['node_search_total']['table']['join'] = array(
+        'node_search_index' => array(
+          'left_field' => 'word',
+          'field' => 'word',
+        ),
+      );
+
+      $data['node_search_dataset']['table']['join'] = array(
+        'node_search_index' => array(
+          'left_field' => 'sid',
+          'field' => 'sid',
+          'extra' => 'node_search_index.type = node_search_dataset.type',
+          'type' => 'INNER',
+        ),
+      );
+
+      $data['node_search_index']['score'] = array(
+        'title' => t('Score'),
+        'help' => t('The score of the search item. This will not be used if the search filter is not also present.'),
+        'field' => array(
+          'id' => 'search_score',
+          'float' => TRUE,
+          'no group by' => TRUE,
+        ),
+        'sort' => array(
+          'id' => 'search_score',
+          'no group by' => TRUE,
+        ),
+      );
+
+      $data['node_search_index']['keys'] = array(
+        'title' => t('Search Keywords'),
+        'help' => t('The keywords to search for.'),
+        'filter' => array(
+          'id' => 'search_keywords',
+          'no group by' => TRUE,
+          'search_type' => 'node_search',
+        ),
+        'argument' => array(
+          'id' => 'search',
+          'no group by' => TRUE,
+          'search_type' => 'node_search',
+        ),
+      );
+
+    }
+  }
+
   return $data;
 }
 
diff --git a/core/modules/search/lib/Drupal/search/Plugin/views/argument/Search.php b/core/modules/search/lib/Drupal/search/Plugin/views/argument/Search.php
index f2dc58b31ba90dd5a3835640ab9cc62f2c9502e1..6dcb8cd0825b66117cec9fc3ddb6fbc4695b5ac0 100644
--- a/core/modules/search/lib/Drupal/search/Plugin/views/argument/Search.php
+++ b/core/modules/search/lib/Drupal/search/Plugin/views/argument/Search.php
@@ -8,9 +8,12 @@
 namespace Drupal\search\Plugin\views\argument;
 
 use Drupal\views\Plugin\views\argument\ArgumentPluginBase;
+use Drupal\views\Plugin\views\display\DisplayPluginBase;
+use Drupal\views\ViewExecutable;
+use Drupal\views\Views;
 
 /**
- * Argument that accepts query keys for search.
+ * Argument handler for search keywords.
  *
  * @ingroup views_argument_handlers
  *
@@ -19,30 +22,53 @@
 class Search extends ArgumentPluginBase {
 
   /**
-   * Make sure that parseSearchExpression is run and everything is set up.
+   * A search query to use for parsing search keywords.
    *
-   * @param $input
-   *    The search phrase which was input by the user.
+   * @var \Drupal\search\ViewsSearchQuery
    */
-  function query_parse_search_expression($input) {
-    if (!isset($this->search_query)) {
-      $this->search_query = db_select('search_index', 'i', array('target' => 'slave'))->extend('Drupal\search\ViewsSearchQuery');
-      $this->search_query->searchExpression($input, $this->view->base_table);
-      $this->search_query->publicParseSearchExpression();
+  protected $searchQuery = NULL;
+
+  /**
+   * The search type name (value of {search_index}.type in the database).
+   *
+   * @var string
+   */
+  protected $searchType;
+
+  /**
+   * {@inheritdoc}
+   */
+  public function init(ViewExecutable $view, DisplayPluginBase $display, array &$options = NULL) {
+    parent::init($view, $display, $options);
+
+    $this->searchType = $this->definition['search_type'];
+  }
+
+  /**
+   * Sets up and parses the search query.
+   *
+   * @param string $input
+   *   The search keywords entered by the user.
+   */
+  protected function queryParseSearchExpression($input) {
+    if (!isset($this->searchQuery)) {
+      $this->searchQuery = db_select('search_index', 'i', array('target' => 'slave'))->extend('Drupal\search\ViewsSearchQuery');
+      $this->searchQuery->searchExpression($input, $this->searchType);
+      $this->searchQuery->publicParseSearchExpression();
     }
   }
 
   /**
-   * Add this argument to the query.
+   * {@inheritdoc}
    */
   public function query($group_by = FALSE) {
     $required = FALSE;
-    $this->query_parse_search_expression($this->argument);
-    if (!isset($this->search_query)) {
+    $this->queryParseSearchExpression($this->argument);
+    if (!isset($this->searchQuery)) {
       $required = TRUE;
     }
     else {
-      $words = $this->search_query->words();
+      $words = $this->searchQuery->words();
       if (empty($words)) {
         $required = TRUE;
       }
@@ -64,28 +90,22 @@ public function query($group_by = FALSE) {
         'left_table' => $search_index,
         'left_field' => 'word',
       );
-      $join = \Drupal::service()->get('plugin.manager.views.join')->createInstance('standard', $definition);
+      $join = Views::pluginManager('join')->createInstance('standard', $definition);
       $search_total = $this->query->addRelationship('search_total', $join, $search_index);
 
       $this->search_score = $this->query->addField('', "SUM($search_index.score * $search_total.count)", 'score', array('aggregate' => TRUE));
 
-      if (empty($this->query->relationships[$this->relationship])) {
-        $base_table = $this->view->storage->get('base_table');
-      }
-      else {
-        $base_table = $this->query->relationships[$this->relationship]['base'];
-      }
-      $search_condition->condition("$search_index.type", $base_table);
+      $search_condition->condition("$search_index.type", $this->searchType);
 
-      if (!$this->search_query->simple()) {
+      if (!$this->searchQuery->simple()) {
         $search_dataset = $this->query->addTable('search_dataset');
-        $conditions = $this->search_query->conditions();
+        $conditions = $this->searchQuery->conditions();
         $condition_conditions =& $conditions->conditions();
         foreach ($condition_conditions  as $key => &$condition) {
           // Make sure we just look at real conditions.
           if (is_numeric($key)) {
             // Replace the conditions with the table alias of views.
-            $this->search_query->condition_replace_string('d.', "$search_dataset.", $condition);
+            $this->searchQuery->conditionReplaceString('d.', "$search_dataset.", $condition);
           }
         }
         $search_conditions =& $search_condition->conditions();
@@ -103,10 +123,14 @@ public function query($group_by = FALSE) {
 
       $this->query->addWhere(0, $search_condition);
       $this->query->addGroupBy("$search_index.sid");
-      $matches = $this->search_query->matches();
+      $matches = $this->searchQuery->matches();
       $placeholder = $this->placeholder();
       $this->query->addHavingExpression(0, "COUNT(*) >= $placeholder", array($placeholder => $matches));
     }
+
+    // Set to NULL to prevent PDO exception when views object is cached
+    // and to clear out memory.
+    $this->searchQuery = NULL;
   }
 
 }
diff --git a/core/modules/search/lib/Drupal/search/Plugin/views/field/Score.php b/core/modules/search/lib/Drupal/search/Plugin/views/field/Score.php
index 0fad572d188c08ffa9ea742950b9f3f4b5f2cd83..ceeb50023fbc13a989b556b61c034802d5ec1a4e 100644
--- a/core/modules/search/lib/Drupal/search/Plugin/views/field/Score.php
+++ b/core/modules/search/lib/Drupal/search/Plugin/views/field/Score.php
@@ -11,7 +11,7 @@
 use Drupal\views\ResultRow;
 
 /**
- * Field handler to provide simple renderer that allows linking to a node.
+ * Field handler for search score.
  *
  * @ingroup views_field_handlers
  *
@@ -19,50 +19,16 @@
  */
 class Score extends Numeric {
 
-  protected function defineOptions() {
-    $options = parent::defineOptions();
-
-    $options['alternate_sort'] = array('default' => '');
-    $options['alternate_order'] = array('default' => 'asc');
-
-    return $options;
-  }
-
-  public function buildOptionsForm(&$form, &$form_state) {
-    $style_options = $this->view->display_handler->getOption('style_options');
-    if (isset($style_options['default']) && $style_options['default'] == $this->options['id']) {
-      $handlers = $this->view->display_handler->getHandlers('field');
-      $options = array('' => t('No alternate'));
-      foreach ($handlers as $id => $handler) {
-        $options[$id] = $handler->adminLabel();
-      }
-
-      $form['alternate_sort'] = array(
-        '#type' => 'select',
-        '#title' => t('Alternative sort'),
-        '#description' => t('Pick an alternative default table sort field to use when the search score field is unavailable.'),
-        '#options' => $options,
-        '#default_value' => $this->options['alternate_sort'],
-      );
-
-      $form['alternate_order'] = array(
-        '#type' => 'select',
-        '#title' => t('Alternate sort order'),
-        '#options' => array('asc' => t('Ascending'), 'desc' => t('Descending')),
-        '#default_value' => $this->options['alternate_order'],
-      );
-    }
-
-    parent::buildOptionsForm($form, $form_state);
-  }
-
+  /**
+   * {@inheritdoc}
+   */
   public function query() {
     // Check to see if the search filter added 'score' to the table.
     // Our filter stores it as $handler->search_score -- and we also
     // need to check its relationship to make sure that we're using the same
     // one or obviously this won't work.
     foreach ($this->view->filter as $handler) {
-      if (isset($handler->search_score) && $handler->relationship == $this->relationship) {
+      if (isset($handler->search_score) && ($handler->relationship == $this->relationship)) {
         $this->field_alias = $handler->search_score;
         $this->tableAlias = $handler->tableAlias;
         return;
@@ -71,13 +37,6 @@ public function query() {
 
     // Hide this field if no search filter is in place.
     $this->options['exclude'] = TRUE;
-    if (!empty($this->options['alternate_sort'])) {
-      if (isset($this->view->style_plugin->options['default']) && $this->view->style_plugin->options['default'] == $this->options['id']) {
-        // Since the style handler initiates fields, we plug these values right into the active handler.
-        $this->view->style_plugin->options['default'] = $this->options['alternate_sort'];
-        $this->view->style_plugin->options['order'] = $this->options['alternate_order'];
-      }
-    }
   }
 
   /**
@@ -89,5 +48,4 @@ public function render(ResultRow $values) {
       return parent::render($values);
     }
   }
-
 }
diff --git a/core/modules/search/lib/Drupal/search/Plugin/views/filter/Search.php b/core/modules/search/lib/Drupal/search/Plugin/views/filter/Search.php
index 708595e76c3155e1e4b4bd8d22ed16b97f205c72..b65e746bd3397e103b057b3fb496631f92018774 100644
--- a/core/modules/search/lib/Drupal/search/Plugin/views/filter/Search.php
+++ b/core/modules/search/lib/Drupal/search/Plugin/views/filter/Search.php
@@ -7,35 +7,58 @@
 
 namespace Drupal\search\Plugin\views\filter;
 
-use Drupal\search\SearchQuery;
 use Drupal\views\Plugin\views\filter\FilterPluginBase;
+use Drupal\views\Plugin\views\display\DisplayPluginBase;
+use Drupal\views\ViewExecutable;
+use Drupal\views\Views;
 
 /**
- * Field handler to provide simple renderer that allows linking to a node.
+ * Filter handler for search keywords.
  *
  * @ingroup views_filter_handlers
  *
- * @PluginID("search")
+ * @PluginID("search_keywords")
  */
 class Search extends FilterPluginBase {
 
+  /**
+   * This filter is always considered multiple-valued.
+   *
+   * @var bool
+   */
   protected $alwaysMultiple = TRUE;
 
   /**
-   * Stores an extended query extender from the search module.
-   *
-   * This value extends the query extender to be able to provide methods
-   * which returns the protected values.
+   * A search query to use for parsing search keywords.
+    *
+    * @var \Drupal\search\ViewsSearchQuery
+    */
+  protected $searchQuery = NULL;
+
+  /**
+   * TRUE if the search query has been parsed.
+   */
+  protected $parsed = FALSE;
+
+  /**
+   * The search type name (value of {search_index}.type in the database).
    *
-   * @var \Drupal\search\ViewsSearchQuery
+   * @var string
    */
-  var $search_query = NULL;
+  protected $searchType;
 
   /**
-   * Checks if the search query has been parsed.
+   * {@inheritdoc}
    */
-  var $parsed = FALSE;
+  public function init(ViewExecutable $view, DisplayPluginBase $display, array &$options = NULL) {
+    parent::init($view, $display, $options);
 
+    $this->searchType = $this->definition['search_type'];
+  }
+
+  /**
+   * {@inheritdoc}
+   */
   protected function defineOptions() {
     $options = parent::defineOptions();
 
@@ -45,7 +68,7 @@ protected function defineOptions() {
   }
 
   /**
-   * Provide simple equality operator
+   * {@inheritdoc}
    */
   protected function operatorForm(&$form, &$form_state) {
     $form['operator'] = array(
@@ -53,27 +76,27 @@ protected function operatorForm(&$form, &$form_state) {
       '#title' => t('On empty input'),
       '#default_value' => $this->operator,
       '#options' => array(
-        'optional' => t('Show All'),
-        'required' => t('Show None'),
+        'optional' => $this->t('Show All'),
+        'required' => $this->t('Show None'),
       ),
     );
   }
 
   /**
-   * Provide a simple textfield for equality
+   * {@inheritdoc}
    */
   protected function valueForm(&$form, &$form_state) {
     $form['value'] = array(
       '#type' => 'textfield',
       '#size' => 15,
       '#default_value' => $this->value,
-      '#attributes' => array('title' => t('Enter the terms you wish to search for.')),
-      '#title' => empty($form_state['exposed']) ? t('Value') : '',
+      '#attributes' => array('title' => $this->t('Search keywords')),
+      '#title' => empty($form_state['exposed']) ? $this->t('Keywords') : '',
     );
   }
 
   /**
-   * Validate the options form.
+   * {@inheritdoc}
    */
   public function validateExposed(&$form, &$form_state) {
     if (!isset($this->options['expose']['identifier'])) {
@@ -82,47 +105,43 @@ public function validateExposed(&$form, &$form_state) {
 
     $key = $this->options['expose']['identifier'];
     if (!empty($form_state['values'][$key])) {
-      $this->query_parse_search_expression($form_state['values'][$key]);
-      if (count($this->search_query->words()) == 0) {
+      $this->queryParseSearchExpression($form_state['values'][$key]);
+      if (count($this->searchQuery->words()) == 0) {
         form_set_error($key, $form_state, format_plural(\Drupal::config('search.settings')->get('index.minimum_word_size'), 'You must include at least one positive keyword with 1 character or more.', 'You must include at least one positive keyword with @count characters or more.'));
       }
     }
   }
 
   /**
-   * Make sure that parseSearchExpression is run and everything is set up.
+   * Sets up and parses the search query.
    *
-   * @param $input
-   *    The search phrase which was input by the user.
+   * @param string $input
+   *   The search keywords entered by the user.
    */
-  function query_parse_search_expression($input) {
-    if (!isset($this->search_query)) {
+  protected function queryParseSearchExpression($input) {
+    if (!isset($this->searchQuery)) {
       $this->parsed = TRUE;
-      $this->search_query = db_select('search_index', 'i', array('target' => 'slave'))->extend('Drupal\search\ViewsSearchQuery');
-      $this->search_query->searchExpression($input, $this->view->base_table);
-      $this->search_query->publicParseSearchExpression();
+      $this->searchQuery = db_select('search_index', 'i', array('target' => 'slave'))->extend('Drupal\search\ViewsSearchQuery');
+      $this->searchQuery->searchExpression($input, $this->searchType);
+      $this->searchQuery->publicParseSearchExpression();
     }
   }
 
   /**
-   * Add this filter to the query.
-   *
-   * Due to the nature of fapi, the value and the operator have an unintended
-   * level of indirection. You will find them in $this->operator
-   * and $this->value respectively.
+   * {@inheritdoc}
    */
   public function query() {
     // Since attachment views don't validate the exposed input, parse the search
     // expression if required.
     if (!$this->parsed) {
-      $this->query_parse_search_expression($this->value);
+      $this->queryParseSearchExpression($this->value);
     }
     $required = FALSE;
-    if (!isset($this->search_query)) {
+    if (!isset($this->searchQuery)) {
       $required = TRUE;
     }
     else {
-      $words = $this->search_query->words();
+      $words = $this->searchQuery->words();
       if (empty($words)) {
         $required = TRUE;
       }
@@ -137,35 +156,30 @@ public function query() {
 
       $search_condition = db_and();
 
-      // Create a new join to relate the 'serach_total' table to our current 'search_index' table.
+      // Create a new join to relate the 'search_total' table to our current
+      // 'search_index' table.
       $definition = array(
         'table' => 'search_total',
         'field' => 'word',
         'left_table' => $search_index,
         'left_field' => 'word',
       );
-      $join = \Drupal::service()->get('plugin.manager.views.join')->createInstance('standard', $definition);
+      $join = Views::pluginManager('join')->createInstance('standard', $definition);
 
       $search_total = $this->query->addRelationship('search_total', $join, $search_index);
 
       $this->search_score = $this->query->addField('', "SUM($search_index.score * $search_total.count)", 'score', array('aggregate' => TRUE));
 
-      if (empty($this->query->relationships[$this->relationship])) {
-        $base_table = $this->view->storage->get('base_table');
-      }
-      else {
-        $base_table = $this->query->relationships[$this->relationship]['base'];
-      }
-      $search_condition->condition("$search_index.type", $base_table);
-      if (!$this->search_query->simple()) {
+      $search_condition->condition("$search_index.type", $this->searchType);
+      if (!$this->searchQuery->simple()) {
         $search_dataset = $this->query->addTable('search_dataset');
-        $conditions = $this->search_query->conditions();
+        $conditions = $this->searchQuery->conditions();
         $condition_conditions =& $conditions->conditions();
         foreach ($condition_conditions  as $key => &$condition) {
           // Make sure we just look at real conditions.
           if (is_numeric($key)) {
             // Replace the conditions with the table alias of views.
-            $this->search_query->condition_replace_string('d.', "$search_dataset.", $condition);
+            $this->searchQuery->conditionReplaceString('d.', "$search_dataset.", $condition);
           }
         }
         $search_conditions =& $search_condition->conditions();
@@ -183,12 +197,12 @@ public function query() {
 
       $this->query->addWhere($this->options['group'], $search_condition);
       $this->query->addGroupBy("$search_index.sid");
-      $matches = $this->search_query->matches();
+      $matches = $this->searchQuery->matches();
       $placeholder = $this->placeholder();
       $this->query->addHavingExpression($this->options['group'], "COUNT(*) >= $placeholder", array($placeholder => $matches));
     }
     // Set to NULL to prevent PDO exception when views object is cached.
-    $this->search_query = NULL;
+    $this->searchQuery = NULL;
   }
 
 }
diff --git a/core/modules/search/lib/Drupal/search/Plugin/views/row/SearchRow.php b/core/modules/search/lib/Drupal/search/Plugin/views/row/SearchRow.php
index ba388cb22b193a0315647c6c9a438bf6434ea74e..8c0709f71511c1c5d14ebfac0fccf3aae1b4531d 100644
--- a/core/modules/search/lib/Drupal/search/Plugin/views/row/SearchRow.php
+++ b/core/modules/search/lib/Drupal/search/Plugin/views/row/SearchRow.php
@@ -10,16 +10,19 @@
 use Drupal\views\Plugin\views\row\RowPluginBase;
 
 /**
- * Plugin which performs a node_view on the resulting object.
+ * Row handler plugin for displaying search results.
  *
  * @ViewsRow(
  *   id = "search_view",
- *   title = @Translation("Search"),
+ *   title = @Translation("Search results"),
  *   help = @Translation("Provides a row plugin to display search results.")
  * )
  */
 class SearchRow extends RowPluginBase {
 
+  /**
+   * {@inheritdoc}
+   */
   protected function defineOptions() {
     $options = parent::defineOptions();
 
@@ -28,6 +31,9 @@ protected function defineOptions() {
     return $options;
   }
 
+  /**
+   * {@inheritdoc}
+   */
   public function buildOptionsForm(&$form, &$form_state) {
     $form['score'] = array(
       '#type' => 'checkbox',
@@ -37,7 +43,7 @@ public function buildOptionsForm(&$form, &$form_state) {
   }
 
   /**
-   * Override the behavior of the render() function.
+   * {@inheritdoc}
    */
   public function render($row) {
     return array(
diff --git a/core/modules/search/lib/Drupal/search/Plugin/views/sort/Score.php b/core/modules/search/lib/Drupal/search/Plugin/views/sort/Score.php
index 589d499a8f00f1963d9d679f2f0ce3796f090d7c..68fcd336b0ca2d49696f76969aebffd71740a735 100644
--- a/core/modules/search/lib/Drupal/search/Plugin/views/sort/Score.php
+++ b/core/modules/search/lib/Drupal/search/Plugin/views/sort/Score.php
@@ -10,7 +10,7 @@
 use Drupal\views\Plugin\views\sort\SortPluginBase;
 
 /**
- * Field handler to provide simple renderer that allows linking to a node.
+ * Sort handler for sorting by search score.
  *
  * @ingroup views_sort_handlers
  *
@@ -18,6 +18,9 @@
  */
 class Score extends SortPluginBase {
 
+  /**
+   * {@inheritdoc}
+   */
   public function query() {
     // Check to see if the search filter/argument added 'score' to the table.
     // Our filter stores it as $handler->search_score -- and we also
@@ -33,8 +36,8 @@ public function query() {
       }
     }
 
-    // Do absolutely nothing if there is no filter/argument in place; there is no reason to
-    // sort on the raw scores with this handler.
+    // Do nothing if there is no filter/argument in place. There is no way
+    // to sort on scores.
   }
 
 }
diff --git a/core/modules/search/lib/Drupal/search/ViewsSearchQuery.php b/core/modules/search/lib/Drupal/search/ViewsSearchQuery.php
index 0690551c4235c14cce544c646d2f6ea8465f1500..f328d3aec62a0509f14cfd7853c181ac5f5584e7 100644
--- a/core/modules/search/lib/Drupal/search/ViewsSearchQuery.php
+++ b/core/modules/search/lib/Drupal/search/ViewsSearchQuery.php
@@ -10,7 +10,7 @@
 use Drupal\Core\Database\Query\Condition;
 
 /**
- * Extends the core SearchQuery to be able to gets it's protected values.
+ * Extends the core SearchQuery to be able to gets its protected values.
  */
 class ViewsSearchQuery extends SearchQuery {
 
@@ -67,14 +67,14 @@ public function publicParseSearchExpression() {
    * @param \Drupal\Core\Database\Query\Condition $condition
    *   The query condition in which the string is replaced.
    */
-  function condition_replace_string($search, $replace, &$condition) {
+  function conditionReplaceString($search, $replace, &$condition) {
     if ($condition['field'] instanceof Condition) {
       $conditions =& $condition['field']->conditions();
       foreach ($conditions as $key => &$subcondition) {
         if (is_numeric($key)) {
           // As conditions can have subconditions, for example db_or(), the
           // function has to be called recursively.
-          $this->condition_replace_string($search, $replace, $subcondition);
+          $this->conditionReplaceString($search, $replace, $subcondition);
         }
       }
     }
diff --git a/core/modules/views/lib/Drupal/views/Tests/DefaultViewsTest.php b/core/modules/views/lib/Drupal/views/Tests/DefaultViewsTest.php
index 31be4abafe684bf8896f182da695df29ae5d2a73..875679f9945e6809543b70540fffd191278b9aff 100644
--- a/core/modules/views/lib/Drupal/views/Tests/DefaultViewsTest.php
+++ b/core/modules/views/lib/Drupal/views/Tests/DefaultViewsTest.php
@@ -103,8 +103,6 @@ protected function setUp() {
 
       $node = $this->drupalCreateNode($values);
 
-      search_index($node->id(), 'node', $node->body->value, Language::LANGCODE_NOT_SPECIFIED);
-
       $comment = array(
         'uid' => $user->id(),
         'status' => CommentInterface::PUBLISHED,
diff --git a/core/modules/views/lib/Drupal/views/Tests/SearchIntegrationTest.php b/core/modules/views/lib/Drupal/views/Tests/SearchIntegrationTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..46d5b037a6e0b8d9fcebe1ffd27248b7133e28a5
--- /dev/null
+++ b/core/modules/views/lib/Drupal/views/Tests/SearchIntegrationTest.php
@@ -0,0 +1,83 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\views\Tests\SearchIntegrationTest.
+ */
+
+namespace Drupal\views\Tests;
+
+/**
+ * Tests search integration filters.
+ */
+class SearchIntegrationTest extends ViewTestBase {
+
+  /**
+   * Modules to enable.
+   *
+   * @var array
+   */
+  public static $modules = array('node', 'search');
+
+  /**
+   * Views used by this test.
+   *
+   * @var array
+   */
+  public static $testViews = array('test_search');
+
+  /**
+   * {inheritdoc}
+   */
+  public static function getInfo() {
+    return array(
+      'name' => 'Search integration tests',
+      'description' => 'Tests search integration filters of views.',
+      'group' => 'Views',
+    );
+  }
+
+  /**
+   * Tests search integration.
+   */
+  public function testSearchIntegration() {
+    // Create a content type.
+    $type = $this->drupalCreateContentType();
+
+    // Add two nodes, one containing the word "pizza" and the other
+    // with the word "sandwich". Make the second node link to the first.
+    $node['title'] = 'pizza';
+    $node['body'] = array(array('value' => 'pizza'));
+    $node['type'] = $type->type;
+    $this->drupalCreateNode($node);
+
+    $this->drupalGet('node/1');
+    $node_url = $this->getUrl();
+
+    $node['title'] = 'sandwich';
+    $node['body'] = array(array('value' => 'sandwich with a <a href="' . $node_url . '">link to first node</a>'));
+    $this->drupalCreateNode($node);
+
+    // Run cron so that the search index tables are updated.
+    $this->cronRun();
+
+    // Test the various views filters by visiting their pages.
+    // These are in the test view 'test_search', and they just display the
+    // titles of the nodes in the result, as links.
+
+    // Page with a keyword filter of 'pizza'.
+    $this->drupalGet('test-filter');
+    $this->assertLink('pizza', 0, 'Pizza page is on Filter page');
+    $this->assertNoLink('sandwich', 'Sandwich page is not on Filter page');
+
+    // Page with a keyword argument.
+    $this->drupalGet('test-arg/pizza');
+    $this->assertLink('pizza', 0, 'Pizza page is on argument page');
+    $this->assertNoLink('sandwich', 'Sandwich page is not on argument page');
+
+    $this->drupalGet('test-arg/sandwich');
+    $this->assertNoLink('pizza', 'Pizza page is not on argument page');
+    $this->assertLink('sandwich', 0, 'Sandwich page is on argument page');
+  }
+
+}
diff --git a/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_search.yml b/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_search.yml
new file mode 100644
index 0000000000000000000000000000000000000000..71443c8a71a3004bbfd475b8dbdd605cf3cdfff0
--- /dev/null
+++ b/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_search.yml
@@ -0,0 +1,248 @@
+base_field: nid
+base_table: node
+core: 8.x
+description: 'Test view for Search integration'
+status: true
+display:
+  page_2:
+    display_plugin: page
+    id: page_2
+    display_title: 'Arg Page'
+    position: 1
+    display_options:
+      display_description: ''
+      filters:
+        status:
+          value: '1'
+          table: node_field_data
+          field: status
+          provider: node
+          id: status
+          expose:
+            operator: ''
+          group: '1'
+      defaults:
+        filters: false
+        filter_groups: false
+        arguments: false
+        title: false
+      filter_groups:
+        operator: AND
+        groups:
+          1: AND
+      path: test-arg/%
+      arguments:
+        keys:
+          id: keys
+          table: node_search_index
+          field: keys
+          relationship: none
+          group_type: group
+          admin_label: ''
+          default_action: 'not found'
+          exception:
+            value: all
+            title_enable: false
+            title: All
+          title_enable: false
+          title: ''
+          default_argument_type: fixed
+          default_argument_options:
+            argument: ''
+          default_argument_skip_url: false
+          summary_options:
+            base_path: ''
+            count: '1'
+            items_per_page: '25'
+            separator: ''
+            override: 0
+            inline: false
+          summary:
+            sort_order: asc
+            number_of_records: 0
+            format: unformatted_summary
+          specify_validation: false
+          validate:
+            type: none
+            fail: 'not found'
+          validate_options: {  }
+          plugin_id: search
+          provider: search
+      title: 'Arg Page'
+  default:
+    display_plugin: default
+    id: default
+    display_title: Master
+    position: 1
+    display_options:
+      access:
+        type: perm
+        options:
+          perm: 'access content'
+      cache:
+        type: none
+        options: {  }
+      query:
+        type: views_query
+        options:
+          disable_sql_rewrite: false
+          distinct: false
+          slave: false
+          query_comment: false
+          query_tags: {  }
+      exposed_form:
+        type: basic
+        options:
+          submit_button: Apply
+          reset_button: false
+          reset_button_label: Reset
+          exposed_sorts_label: 'Sort by'
+          expose_sort_order: true
+          sort_asc_label: Asc
+          sort_desc_label: Desc
+      pager:
+        type: none
+        options:
+          items_per_page: '0'
+          offset: 0
+      style:
+        type: default
+        options:
+          grouping: {  }
+          row_class: ''
+          default_row_class: true
+          row_class_special: true
+      row:
+        type: fields
+      fields:
+        title:
+          id: title
+          table: node_field_data
+          field: title
+          provider: node
+          alter:
+            alter_text: false
+            make_link: false
+            absolute: false
+            trim: false
+            word_boundary: false
+            ellipsis: false
+            strip_tags: false
+            html: false
+          hide_empty: false
+          empty_zero: false
+          link_to_node: 1
+          relationship: none
+          group_type: group
+          admin_label: ''
+          label: Title
+          exclude: false
+          element_type: ''
+          element_class: ''
+          element_label_type: ''
+          element_label_class: ''
+          element_label_colon: true
+          element_wrapper_type: ''
+          element_wrapper_class: ''
+          element_default_classes: true
+          empty: ''
+          hide_alter_empty: true
+      filters:
+        status:
+          value: '1'
+          table: node_field_data
+          field: status
+          provider: node
+          id: status
+          expose:
+            operator: ''
+          group: '1'
+      sorts:
+        created:
+          id: created
+          table: node_field_data
+          field: created
+          order: DESC
+          relationship: none
+          group_type: group
+          admin_label: ''
+          exposed: false
+          expose:
+            label: ''
+          granularity: second
+      title: ''
+      header: {  }
+      footer: {  }
+      empty: {  }
+      relationships: {  }
+      arguments: {  }
+  page_1:
+    display_plugin: page
+    id: page_1
+    display_title: 'Filter Page'
+    position: 1
+    display_options:
+      display_description: ''
+      filters:
+        status:
+          value: '1'
+          table: node_field_data
+          field: status
+          provider: node
+          id: status
+          expose:
+            operator: ''
+          group: '1'
+        keys:
+          id: keys
+          table: node_search_index
+          field: keys
+          relationship: none
+          group_type: group
+          admin_label: ''
+          operator: optional
+          value: pizza
+          group: '1'
+          exposed: false
+          expose:
+            operator_id: ''
+            label: ''
+            description: ''
+            use_operator: false
+            operator: ''
+            identifier: ''
+            required: false
+            remember: false
+            multiple: false
+            remember_roles:
+              authenticated: authenticated
+          is_grouped: false
+          group_info:
+            label: ''
+            description: ''
+            identifier: ''
+            optional: true
+            widget: select
+            multiple: false
+            remember: 0
+            default_group: All
+            default_group_multiple: {  }
+            group_items: {  }
+          plugin_id: search_keywords
+          provider: search
+      defaults:
+        filters: false
+        filter_groups: false
+        title: false
+      filter_groups:
+        operator: AND
+        groups:
+          1: AND
+      path: test-filter
+      title: 'Filter Page'
+label: 'Search Test'
+module: views
+id: test_search
+tag: ''
+uuid: f19c4fd2-af74-4d70-8500-a1037ca434bb
+langcode: en