diff --git a/core/modules/node/src/Plugin/views/row/Rss.php b/core/modules/node/src/Plugin/views/row/Rss.php index ebb8b1afd2..01b5d2754f 100644 --- a/core/modules/node/src/Plugin/views/row/Rss.php +++ b/core/modules/node/src/Plugin/views/row/Rss.php @@ -110,12 +110,14 @@ public function render($row) { // The node gets built and modules add to or modify $node->rss_elements // and $node->rss_namespaces. - $build_mode = $display_mode; $build = \Drupal::entityTypeManager() ->getViewBuilder('node') ->view($node, $build_mode); + // Add rss key to cache to differentiate this from other caches. + $build['#cache']['keys'][] = 'view_rss'; + unset($build['#theme']); if (!empty($node->rss_namespaces)) { diff --git a/core/modules/node/tests/modules/node_test_views/test_views/views.view.test_node_article_feed.yml b/core/modules/node/tests/modules/node_test_views/test_views/views.view.test_node_article_feed.yml new file mode 100644 index 0000000000..089e263a9d --- /dev/null +++ b/core/modules/node/tests/modules/node_test_views/test_views/views.view.test_node_article_feed.yml @@ -0,0 +1,207 @@ +langcode: en +status: true +dependencies: + config: + - core.entity_view_mode.node.teaser + - node.type.article + module: + - node + - user +id: test_node_article_feed +label: 'Test Node Article Feed' +module: views +description: '' +tag: '' +base_table: node_field_data +base_field: nid +display: + default: + display_plugin: default + id: default + display_title: Master + position: 0 + display_options: + access: + type: perm + options: + perm: 'access content' + cache: + type: tag + options: { } + query: + type: views_query + options: + disable_sql_rewrite: false + distinct: false + replica: false + query_comment: '' + 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: mini + options: + items_per_page: 10 + offset: 0 + id: 0 + total_pages: null + expose: + items_per_page: false + items_per_page_label: 'Items per page' + items_per_page_options: '5, 10, 25, 50' + items_per_page_options_all: false + items_per_page_options_all_label: '- All -' + offset: false + offset_label: Offset + tags: + previous: ‹‹ + next: ›› + style: + type: default + options: + grouping: { } + row_class: '' + default_row_class: true + uses_fields: false + row: + type: fields + options: + inline: { } + separator: '' + hide_empty: false + default_field_elements: true + fields: + title: + id: title + table: node_field_data + field: title + entity_type: node + entity_field: title + label: '' + 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 + settings: + link_to_entity: true + plugin_id: field + relationship: none + group_type: group + admin_label: '' + 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 + click_sort_column: value + type: string + group_column: value + group_columns: { } + group_rows: true + delta_limit: 0 + delta_offset: 0 + delta_reversed: false + delta_first_last: false + multi_type: separator + separator: ', ' + field_api_classes: false + filters: + status: + value: '1' + table: node_field_data + field: status + plugin_id: boolean + entity_type: node + entity_field: status + id: status + expose: + operator: '' + operator_limit_selection: false + operator_list: { } + group: 1 + type: + id: type + table: node_field_data + field: type + value: + article: article + entity_type: node + entity_field: type + plugin_id: bundle + expose: + operator_limit_selection: false + operator_list: { } + sorts: + created: + id: created + table: node_field_data + field: created + order: DESC + entity_type: node + entity_field: created + plugin_id: date + relationship: none + group_type: group + admin_label: '' + exposed: false + expose: + label: '' + granularity: second + header: { } + footer: { } + empty: { } + relationships: { } + arguments: { } + display_extenders: { } + cache_metadata: + max-age: -1 + contexts: + - 'languages:language_content' + - 'languages:language_interface' + - url.query_args + - 'user.node_grants:view' + - user.permissions + tags: { } + feed_1: + display_plugin: feed + id: feed_1 + display_title: 'Test Feed' + position: 1 + display_options: + display_extenders: { } + row: + type: node_rss + options: + relationship: none + view_mode: teaser + path: test-node-article-feed + display_description: '' + cache_metadata: + max-age: -1 + contexts: + - 'languages:language_content' + - 'languages:language_interface' + - 'user.node_grants:view' + - user.permissions + tags: { } diff --git a/core/modules/node/tests/src/Functional/NodeRssCacheTest.php b/core/modules/node/tests/src/Functional/NodeRssCacheTest.php new file mode 100644 index 0000000000..9bc92cc23b --- /dev/null +++ b/core/modules/node/tests/src/Functional/NodeRssCacheTest.php @@ -0,0 +1,87 @@ +drupalCreateUser([ + 'bypass node access', + 'access content', + 'create article content', + ]); + $this->drupalLogin($user); + } + + /** + * Ensure the RSS teaser render does not interfere with default theme cache. + */ + public function testNodeRssCacheContent() { + // Only the plain_text text format is available by default, which escapes + // all HTML. + FilterFormat::create([ + 'format' => 'full_html', + 'name' => 'Full HTML', + 'filters' => [], + ])->save(); + + // Create the test node. + $node = $this->drupalCreateNode([ + 'type' => 'article', + 'promote' => 1, + 'title' => 'Article Test Title', + 'body' => [ + 'value' => '

Article test text.

', + 'format' => 'full_html', + ], + ]); + + // Render the node in the RSS feed view as a teaser. + $this->drupalGet('test-node-article-feed'); + + // Render the teaser normally. + $viewBuilder = $this->container->get('entity_type.manager')->getViewBuilder('node'); + $build = $viewBuilder->view($node, 'teaser'); + $output = $this->container->get('renderer')->renderPlain($build); + + // Teaser must contain an "assertStringContainsString('__toString()); + } + +}