diff --git a/core/modules/comment/comment.module b/core/modules/comment/comment.module index fa5caee..95e0418 100644 --- a/core/modules/comment/comment.module +++ b/core/modules/comment/comment.module @@ -543,7 +543,7 @@ function comment_entity_view(EntityInterface $entity, EntityDisplay $display, $v } } } - elseif ($view_mode != 'search_index' && $view_mode != 'search_result') { + elseif ($view_mode != 'search_index' && $view_mode != 'search_result' && $view_mode != 'search_result_extra') { // Entity in other view modes: add a "post comment" link if the user is // allowed to post comments and if this entity is allowing new comments. // But we don't want this link if we're building the entity for search diff --git a/core/modules/node/lib/Drupal/node/Plugin/Search/NodeSearch.php b/core/modules/node/lib/Drupal/node/Plugin/Search/NodeSearch.php index 087944e..7d3effb 100644 --- a/core/modules/node/lib/Drupal/node/Plugin/Search/NodeSearch.php +++ b/core/modules/node/lib/Drupal/node/Plugin/Search/NodeSearch.php @@ -229,7 +229,7 @@ public function execute() { $node_render = $this->entityManager->getViewBuilder('node'); foreach ($find as $item) { - // Render the node. + // Render the node for the excerpt. $node = $node_storage->load($item->sid)->getTranslation($item->langcode); $build = $node_render->view($node, 'search_result', $item->langcode); unset($build['#theme']); @@ -238,6 +238,22 @@ public function execute() { // Fetch comment count for snippet. $node->rendered .= ' ' . $this->moduleHandler->invoke('comment', 'node_update_index', array($node, $item->langcode)); + // Render the node for the extra fields, but only if it has been + // customized for this content type. + $display = entity_load('entity_display', 'node.' . $node->bundle() . '.search_result_extra'); + if ($display) { + $build = $node_render->view($node, 'search_result_extra', $item->langcode); + // Remove some components "helpfully" added automatically during node + // view building. + unset($build['title']); + unset($build['links']); + unset($build['#theme']); + $node->extra_rendered = drupal_render($build); + } + else { + $node->extra_rendered = ''; + } + $extra = $this->moduleHandler->invokeAll('node_search_result', array($node, $item->langcode)); $language = language_load($item->langcode); @@ -256,6 +272,7 @@ public function execute() { 'extra' => $extra, 'score' => $item->calculated_score, 'snippet' => search_excerpt($keys, $node->rendered, $item->langcode), + 'rendered' => $node->extra_rendered, 'langcode' => $node->language()->id, ); } diff --git a/core/modules/search/config/entity.view_mode.node.search_result.yml b/core/modules/search/config/entity.view_mode.node.search_result.yml index cfdc1ac..0e1f09d 100644 --- a/core/modules/search/config/entity.view_mode.node.search_result.yml +++ b/core/modules/search/config/entity.view_mode.node.search_result.yml @@ -1,6 +1,6 @@ id: node.search_result uuid: 095d7357-de7d-4acc-953a-585cd106e89b -label: Search result +label: Search result excerpt status: false cache: true targetEntityType: node diff --git a/core/modules/search/config/entity.view_mode.node.search_result_extra.yml b/core/modules/search/config/entity.view_mode.node.search_result_extra.yml new file mode 100644 index 0000000..ca425ae --- /dev/null +++ b/core/modules/search/config/entity.view_mode.node.search_result_extra.yml @@ -0,0 +1,6 @@ +id: node.search_result_extra +uuid: 9ffc2b11-b47f-466b-bf00-b3bac1d3a55f +label: 'Search result display' +targetEntityType: node +status: false +cache: true diff --git a/core/modules/search/lib/Drupal/search/Tests/SearchFieldsTest.php b/core/modules/search/lib/Drupal/search/Tests/SearchFieldsTest.php new file mode 100644 index 0000000..0a8508a --- /dev/null +++ b/core/modules/search/lib/Drupal/search/Tests/SearchFieldsTest.php @@ -0,0 +1,184 @@ + 'Search fields and display modes', + 'description' => 'Verifies that fields can be managed with display modes for indexing, excerpts, and display', + 'group' => 'Search', + ); + } + + function setUp() { + parent::setUp(); + + // Create a new content type. + $type = 'sft_bundle'; + $this->drupalCreateContentType(array('type' => $type, 'name' => $type)); + + // Create a test user who can manage content types and fields. + $test_user = $this->drupalCreateUser(array('access content', 'search content', 'administer nodes', 'administer content types', 'administer node fields', 'administer node display', 'create sft_bundle content', 'access site reports', 'administer site configuration')); + $this->drupalLogin($test_user); + + // Add some text fields to the content type (default settings). + $fields = array('for_index', 'for_excerpt', 'for_display'); + foreach ($fields as $field) { + $this->drupalPostForm('admin/structure/types/manage/' . $type . '/fields', + array( + 'fields[_add_new_field][label]' => $field, + 'fields[_add_new_field][type]' => 'text', + 'fields[_add_new_field][field_name]' => $field, + ), t('Save')); + $this->drupalPostForm(NULL, array(), t('Save field settings')); + $this->drupalPostForm(NULL, array(), t('Save settings')); + }; + + // Configure the Search display modes to each show only one of the three + // fields. + $this->drupalPostForm('admin/structure/types/manage/' . $type . '/display', + array( + 'display_modes_custom[search_index]' => TRUE, + 'display_modes_custom[search_result]' => TRUE, + 'display_modes_custom[search_result_extra]' => TRUE, + ), t('Save')); + + $this->drupalPostForm('admin/structure/types/manage/' . $type . '/display/search_index', + array( + 'fields[field_for_excerpt][type]' => 'hidden', + 'fields[field_for_display][type]' => 'hidden', + ), t('Save')); + $this->drupalPostForm('admin/structure/types/manage/' . $type . '/display/search_result', + array( + 'fields[field_for_index][type]' => 'hidden', + 'fields[field_for_display][type]' => 'hidden', + ), t('Save')); + $this->drupalPostForm('admin/structure/types/manage/' . $type . '/display/search_result_extra', + array( + 'fields[field_for_index][type]' => 'hidden', + 'fields[field_for_excerpt][type]' => 'hidden', + ), t('Save')); + + // Clear all caches, because this test does not appear to work otherwise. + $this->drupalPostForm('admin/config/development/performance', array(), t('Clear all caches')); + + // Create a node with different values in the 3 fields. + $this->drupalPostForm('node/add/' . $type, + array( + 'title[0][value]' => 'Title header', + 'field_for_index[0][value]' => 'index contents database', + 'field_for_excerpt[0][value]' => 'excerpt snippet highlighted', + 'field_for_display[0][value]' => 'display output formatted', + ), t('Save and publish')); + $node = node_load(1, TRUE); + $node = $node->getUntranslated(); + $this->node = $node; + + // Update the search index. + $this->container->get('plugin.manager.search')->createInstance('node_search')->updateIndex(); + search_update_totals(); + + $this->drupalGet('admin/reports/dblog'); + } + + /** + * Tests that the search field display modes work correctly. + */ + function testSearchFieldDisplays() { + // Reality check: verify that the information is on the node. + $this->drupalGet('node/' . $this->node->id()); + $this->assertText('index contents database', 'Index text is on the node'); + $this->assertText('excerpt snippet highlighted', 'Excerpt text is on the node'); + $this->assertText('display output formatted', 'Display text is on the node'); + + // Reality check: verify that the display modes are working. + $build = node_view($this->node, 'default'); + $out = drupal_render($build); + $this->assertTrue(strpos($out, 'index contents database') > 0, 'Index text is present in full view mode (' . strip_tags($out) . ')'); + $this->assertTrue(strpos($out, 'excerpt snippet highlighted') > 0, 'Excerpt text is not present in full view mode'); + $this->assertTrue(strpos($out, 'display output formatted') > 0, 'Display text is not present in full view mode'); + + $build = node_view($this->node, 'search_index'); + $out = drupal_render($build); + $this->assertTrue(strpos($out, 'index contents database') > 0, 'Index text is present in index view mode (' . strip_tags($out) . ')'); + $this->assertFalse(strpos($out, 'excerpt snippet highlighted') > 0, 'Excerpt text is not present in index view mode'); + $this->assertFalse(strpos($out, 'display output formatted') > 0, 'Display text is not present in index view mode'); + + $build = node_view($this->node, 'search_result'); + $out = drupal_render($build); + $this->assertFalse(strpos($out, 'index contents database') > 0, 'Index text is not present in excerpt view mode (' . strip_tags($out) . ')'); + $this->assertTrue(strpos($out, 'excerpt snippet highlighted') > 0, 'Excerpt text is present in excerpt view mode'); + $this->assertFalse(strpos($out, 'display output formatted') > 0, 'Display text is not present in excerpt view mode'); + + $build = node_view($this->node, 'search_result_extra'); + $out = drupal_render($build); + $this->assertFalse(strpos($out, 'index contents database') > 0, 'Index text is present not in result view mode (' . strip_tags($out) . ')'); + $this->assertFalse(strpos($out, 'excerpt snippet highlighted') > 0, 'Excerpt text is not present in result view mode'); + $this->assertTrue(strpos($out, 'display output formatted') > 0, 'Display text is present in result view mode'); + + // Verify that if we search for excerpt or display words, we find nothing + // because they are not in the index. + $this->drupalPostForm('search/node', array('keys' => 'excerpt'), t('Search')); + $this->assertText('no results', 'Search for words not in index did not find a match'); + $this->drupalPostForm('search/node', array('keys' => 'display'), t('Search')); + $this->assertText('no results', 'Search for words not in index did not find a match'); + + // Verify that if we search for index words or node title, we find it, + // and that the display words are shown. + $this->drupalPostForm('search/node', array('keys' => 'index'), t('Search')); + $this->assertNoText('no results', 'Search for words in index did find a match'); + $this->assertText($this->node->label(), 'Node title is displayed'); + $this->assertText('display output formatted', 'Display field is displayed'); + + $this->drupalPostForm('search/node', array('keys' => $this->node->label()), t('Search')); + $this->assertNoText('no results', 'Search for node title did find a match'); + $this->assertText('display output formatted', 'Display field is displayed'); + + // Verify that if we search for index words with an excerpt and display + // word also OR'd into the search string, the excerpt word is highlighted + // but not the index or display word. Also verify that all the display words + // are shown, and the index words not in the query are missing. + $this->drupalPostForm('search/node', array('keys' => 'excerpt OR index OR display'), t('Search')); + $this->assertText('display output formatted', 'Display field is displayed'); + $this->assertText($this->node->label(), 'Node title is displayed'); + $this->assertRaw('excerpt', 'Excerpt word is highlighted'); + $this->assertNoRaw('display', 'Display word is not highlighted'); + $this->assertNoRaw('index', 'Index word is not highlighted'); + $this->assertNoText('contents', 'Other index word is not present'); + $this->assertNoText('database', 'Other index word is not present'); + + // Turn off the customized display of Search Results Extra. + $this->drupalPostForm('admin/structure/types/manage/sft_bundle/display', + array( + 'display_modes_custom[search_result_extra]' => FALSE, + ), t('Save')); + // Verify that the display stuff is now not displayed in search results. + $this->drupalPostForm('search/node', array('keys' => 'index'), t('Search')); + $this->assertNoText('display output formatted', 'Display field is not displayed'); + $this->assertText($this->node->label(), 'Node title is displayed'); + $this->assertNoText('no results', 'Search for words in index did find a match'); + + } +} diff --git a/core/modules/search/search.pages.inc b/core/modules/search/search.pages.inc index 023a825..d82eaef 100644 --- a/core/modules/search/search.pages.inc +++ b/core/modules/search/search.pages.inc @@ -83,8 +83,9 @@ function template_preprocess_search_result(&$variables) { if (isset($result['extra']) && is_array($result['extra'])) { $info = array_merge($info, $result['extra']); } - // Check for existence. User search does not include snippets. + // Check for existence. User search does not include snippets or rendered. $variables['snippet'] = isset($result['snippet']) ? $result['snippet'] : ''; + $variables['rendered'] = isset($result['rendered']) ? $result['rendered'] : ''; // Provide separated and grouped meta information.. $variables['info_split'] = $info; $variables['info'] = implode(' - ', $info); diff --git a/core/modules/search/templates/search-result.html.twig b/core/modules/search/templates/search-result.html.twig index 281f8b1..2f2fc4e 100644 --- a/core/modules/search/templates/search-result.html.twig +++ b/core/modules/search/templates/search-result.html.twig @@ -11,6 +11,8 @@ * - url: URL of the result. * - title: Title of the result. * - snippet: A small preview of the result. Does not apply to user searches. + * - rendered: Extra fields to display with the result. Does not apply to user + * searches. * - info: String of all the meta information ready for print. Does not apply * to user searches. * - plugin_id: The machine-readable name of the plugin being executed,such @@ -67,6 +69,9 @@ {% if snippet %}

{{ snippet }}

{% endif %} + {% if rendered %} +
{{ rendered }}
+ {% endif %} {% if info %}

{{ info }}

{% endif %}