Issue #2500931 by mikeker, jhedstrom, Berdir: Views feed doesn't encode embedded HTML anymore
parent
9f74e47286
commit
30c6960459
|
@ -50,7 +50,6 @@ class Rss extends RssPluginBase {
|
||||||
|
|
||||||
$item = new \stdClass();
|
$item = new \stdClass();
|
||||||
foreach ($entity as $name => $field) {
|
foreach ($entity as $name => $field) {
|
||||||
// views_view_row_rss takes care about the escaping.
|
|
||||||
$item->{$name} = $field->value;
|
$item->{$name} = $field->value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -84,8 +84,6 @@ class Rss extends RssPluginBase {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$description_build = [];
|
|
||||||
|
|
||||||
$comment->link = $comment->url('canonical', array('absolute' => TRUE));
|
$comment->link = $comment->url('canonical', array('absolute' => TRUE));
|
||||||
$comment->rss_namespaces = array();
|
$comment->rss_namespaces = array();
|
||||||
$comment->rss_elements = array(
|
$comment->rss_elements = array(
|
||||||
|
@ -113,13 +111,11 @@ class Rss extends RssPluginBase {
|
||||||
$this->view->style_plugin->namespaces = array_merge($this->view->style_plugin->namespaces, $comment->rss_namespaces);
|
$this->view->style_plugin->namespaces = array_merge($this->view->style_plugin->namespaces, $comment->rss_namespaces);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$item = new \stdClass();
|
||||||
if ($view_mode != 'title') {
|
if ($view_mode != 'title') {
|
||||||
// We render comment contents.
|
// We render comment contents.
|
||||||
$description_build = $build;
|
$item->description = $build;
|
||||||
}
|
}
|
||||||
|
|
||||||
$item = new \stdClass();
|
|
||||||
$item->description = $description_build;
|
|
||||||
$item->title = $comment->label();
|
$item->title = $comment->label();
|
||||||
$item->link = $comment->link;
|
$item->link = $comment->link;
|
||||||
// Provide a reference so that the render call in
|
// Provide a reference so that the render call in
|
||||||
|
|
|
@ -108,8 +108,6 @@ class Rss extends RssPluginBase {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$description_build = [];
|
|
||||||
|
|
||||||
$node->link = $node->url('canonical', array('absolute' => TRUE));
|
$node->link = $node->url('canonical', array('absolute' => TRUE));
|
||||||
$node->rss_namespaces = array();
|
$node->rss_namespaces = array();
|
||||||
$node->rss_elements = array(
|
$node->rss_elements = array(
|
||||||
|
@ -149,13 +147,11 @@ class Rss extends RssPluginBase {
|
||||||
$this->view->style_plugin->namespaces += $xml_rdf_namespaces;
|
$this->view->style_plugin->namespaces += $xml_rdf_namespaces;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$item = new \stdClass();
|
||||||
if ($display_mode != 'title') {
|
if ($display_mode != 'title') {
|
||||||
// We render node contents.
|
// We render node contents.
|
||||||
$description_build = $build;
|
$item->description = $build;
|
||||||
}
|
}
|
||||||
|
|
||||||
$item = new \stdClass();
|
|
||||||
$item->description = $description_build;
|
|
||||||
$item->title = $node->label();
|
$item->title = $node->label();
|
||||||
$item->link = $node->link;
|
$item->link = $node->link;
|
||||||
// Provide a reference so that the render call in
|
// Provide a reference so that the render call in
|
||||||
|
|
|
@ -147,8 +147,10 @@ class RssFields extends RowPluginBase {
|
||||||
// @todo Views should expect and store a leading /. See:
|
// @todo Views should expect and store a leading /. See:
|
||||||
// https://www.drupal.org/node/2423913
|
// https://www.drupal.org/node/2423913
|
||||||
$item->link = Url::fromUserInput('/' . $this->getField($row_index, $this->options['link_field']))->setAbsolute()->toString();
|
$item->link = Url::fromUserInput('/' . $this->getField($row_index, $this->options['link_field']))->setAbsolute()->toString();
|
||||||
|
|
||||||
$field = $this->getField($row_index, $this->options['description_field']);
|
$field = $this->getField($row_index, $this->options['description_field']);
|
||||||
$item->description = is_array($field) ? $field : ['#markup' => $field];
|
$item->description = is_array($field) ? $field : ['#markup' => $field];
|
||||||
|
|
||||||
$item->elements = array(
|
$item->elements = array(
|
||||||
array('key' => 'pubDate', 'value' => $this->getField($row_index, $this->options['date_field'])),
|
array('key' => 'pubDate', 'value' => $this->getField($row_index, $this->options['date_field'])),
|
||||||
array(
|
array(
|
||||||
|
|
|
@ -48,9 +48,13 @@ class DisplayFeedTest extends PluginTestBase {
|
||||||
|
|
||||||
// Verify a title with HTML entities is properly escaped.
|
// Verify a title with HTML entities is properly escaped.
|
||||||
$node_title = 'This "cool" & "neat" article\'s title';
|
$node_title = 'This "cool" & "neat" article\'s title';
|
||||||
$node = $this->drupalCreateNode(array(
|
$node = $this->drupalCreateNode([
|
||||||
'title' => $node_title
|
'title' => $node_title,
|
||||||
));
|
'body' => [0 => [
|
||||||
|
'value' => 'A paragraph',
|
||||||
|
'format' => filter_default_format(),
|
||||||
|
]],
|
||||||
|
]);
|
||||||
|
|
||||||
// Test the site name setting.
|
// Test the site name setting.
|
||||||
$site_name = $this->randomMachineName();
|
$site_name = $this->randomMachineName();
|
||||||
|
@ -60,6 +64,8 @@ class DisplayFeedTest extends PluginTestBase {
|
||||||
$result = $this->xpath('//title');
|
$result = $this->xpath('//title');
|
||||||
$this->assertEqual($result[0], $site_name, 'The site title is used for the feed title.');
|
$this->assertEqual($result[0], $site_name, 'The site title is used for the feed title.');
|
||||||
$this->assertEqual($result[1], $node_title, 'Node title with HTML entities displays correctly.');
|
$this->assertEqual($result[1], $node_title, 'Node title with HTML entities displays correctly.');
|
||||||
|
// Verify HTML is properly escaped in the description field.
|
||||||
|
$this->assertRaw('<p>A paragraph</p>');
|
||||||
|
|
||||||
$view = $this->container->get('entity.manager')->getStorage('view')->load('test_display_feed');
|
$view = $this->container->get('entity.manager')->getStorage('view')->load('test_display_feed');
|
||||||
$display = &$view->getDisplay('feed_1');
|
$display = &$view->getDisplay('feed_1');
|
||||||
|
@ -101,12 +107,18 @@ class DisplayFeedTest extends PluginTestBase {
|
||||||
// Verify a title with HTML entities is properly escaped.
|
// Verify a title with HTML entities is properly escaped.
|
||||||
$node_title = 'This "cool" & "neat" article\'s title';
|
$node_title = 'This "cool" & "neat" article\'s title';
|
||||||
$this->drupalCreateNode(array(
|
$this->drupalCreateNode(array(
|
||||||
'title' => $node_title
|
'title' => $node_title,
|
||||||
|
'body' => [0 => [
|
||||||
|
'value' => 'A paragraph',
|
||||||
|
'format' => filter_default_format(),
|
||||||
|
]],
|
||||||
));
|
));
|
||||||
|
|
||||||
$this->drupalGet('test-feed-display-fields.xml');
|
$this->drupalGet('test-feed-display-fields.xml');
|
||||||
$result = $this->xpath('//title/a');
|
$result = $this->xpath('//title/a');
|
||||||
$this->assertEqual($result[0], $node_title, 'Node title with HTML entities displays correctly.');
|
$this->assertEqual($result[0], $node_title, 'Node title with HTML entities displays correctly.');
|
||||||
|
// Verify HTML is properly escaped in the description field.
|
||||||
|
$this->assertRaw('<p>A paragraph</p>');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -1,8 +1,12 @@
|
||||||
langcode: en
|
langcode: en
|
||||||
status: true
|
status: true
|
||||||
dependencies:
|
dependencies:
|
||||||
|
config:
|
||||||
|
- core.entity_view_mode.node.teaser
|
||||||
|
- field.storage.node.body
|
||||||
module:
|
module:
|
||||||
- node
|
- node
|
||||||
|
- text
|
||||||
- user
|
- user
|
||||||
id: test_display_feed
|
id: test_display_feed
|
||||||
label: test_display_feed
|
label: test_display_feed
|
||||||
|
@ -41,6 +45,68 @@ display:
|
||||||
plugin_id: field
|
plugin_id: field
|
||||||
entity_type: node
|
entity_type: node
|
||||||
entity_field: title
|
entity_field: title
|
||||||
|
body:
|
||||||
|
id: body
|
||||||
|
table: node__body
|
||||||
|
field: body
|
||||||
|
relationship: none
|
||||||
|
group_type: group
|
||||||
|
admin_label: ''
|
||||||
|
label: ''
|
||||||
|
exclude: false
|
||||||
|
alter:
|
||||||
|
alter_text: false
|
||||||
|
text: ''
|
||||||
|
make_link: false
|
||||||
|
path: ''
|
||||||
|
absolute: false
|
||||||
|
external: false
|
||||||
|
replace_spaces: false
|
||||||
|
path_case: none
|
||||||
|
trim_whitespace: false
|
||||||
|
alt: ''
|
||||||
|
rel: ''
|
||||||
|
link_class: ''
|
||||||
|
prefix: ''
|
||||||
|
suffix: ''
|
||||||
|
target: ''
|
||||||
|
nl2br: false
|
||||||
|
max_length: 0
|
||||||
|
word_boundary: true
|
||||||
|
ellipsis: true
|
||||||
|
more_link: false
|
||||||
|
more_link_text: ''
|
||||||
|
more_link_path: ''
|
||||||
|
strip_tags: false
|
||||||
|
trim: false
|
||||||
|
preserve_tags: ''
|
||||||
|
html: false
|
||||||
|
element_type: ''
|
||||||
|
element_class: ''
|
||||||
|
element_label_type: ''
|
||||||
|
element_label_class: ''
|
||||||
|
element_label_colon: false
|
||||||
|
element_wrapper_type: ''
|
||||||
|
element_wrapper_class: ''
|
||||||
|
element_default_classes: true
|
||||||
|
empty: ''
|
||||||
|
hide_empty: false
|
||||||
|
empty_zero: false
|
||||||
|
hide_alter_empty: true
|
||||||
|
click_sort_column: value
|
||||||
|
type: text_default
|
||||||
|
settings: { }
|
||||||
|
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
|
||||||
|
plugin_id: field
|
||||||
filters:
|
filters:
|
||||||
status:
|
status:
|
||||||
expose:
|
expose:
|
||||||
|
@ -75,10 +141,21 @@ display:
|
||||||
style:
|
style:
|
||||||
type: default
|
type: default
|
||||||
title: test_display_feed
|
title: test_display_feed
|
||||||
|
display_extenders: { }
|
||||||
display_plugin: default
|
display_plugin: default
|
||||||
display_title: Master
|
display_title: Master
|
||||||
id: default
|
id: default
|
||||||
position: 0
|
position: 0
|
||||||
|
cache_metadata:
|
||||||
|
contexts:
|
||||||
|
- 'languages:language_content'
|
||||||
|
- 'languages:language_interface'
|
||||||
|
- url.query_args
|
||||||
|
- 'user.node_grants:view'
|
||||||
|
- user.permissions
|
||||||
|
max-age: -1
|
||||||
|
tags:
|
||||||
|
- 'config:field.storage.node.body'
|
||||||
feed_1:
|
feed_1:
|
||||||
display_options:
|
display_options:
|
||||||
displays: { }
|
displays: { }
|
||||||
|
@ -90,10 +167,20 @@ display:
|
||||||
style:
|
style:
|
||||||
type: rss
|
type: rss
|
||||||
sitename_title: true
|
sitename_title: true
|
||||||
|
display_extenders: { }
|
||||||
display_plugin: feed
|
display_plugin: feed
|
||||||
display_title: Feed
|
display_title: Feed
|
||||||
id: feed_1
|
id: feed_1
|
||||||
position: 0
|
position: 0
|
||||||
|
cache_metadata:
|
||||||
|
contexts:
|
||||||
|
- 'languages:language_content'
|
||||||
|
- 'languages:language_interface'
|
||||||
|
- 'user.node_grants:view'
|
||||||
|
- user.permissions
|
||||||
|
max-age: -1
|
||||||
|
tags:
|
||||||
|
- 'config:field.storage.node.body'
|
||||||
feed_2:
|
feed_2:
|
||||||
display_options:
|
display_options:
|
||||||
displays: { }
|
displays: { }
|
||||||
|
@ -105,7 +192,7 @@ display:
|
||||||
options:
|
options:
|
||||||
title_field: title
|
title_field: title
|
||||||
link_field: title
|
link_field: title
|
||||||
description_field: title
|
description_field: body
|
||||||
creator_field: title
|
creator_field: title
|
||||||
date_field: title
|
date_field: title
|
||||||
guid_field_options:
|
guid_field_options:
|
||||||
|
@ -115,14 +202,35 @@ display:
|
||||||
type: rss
|
type: rss
|
||||||
sitename_title: true
|
sitename_title: true
|
||||||
display_description: ''
|
display_description: ''
|
||||||
|
display_extenders: { }
|
||||||
display_plugin: feed
|
display_plugin: feed
|
||||||
display_title: 'Feed with Fields'
|
display_title: 'Feed with Fields'
|
||||||
id: feed_2
|
id: feed_2
|
||||||
position: 0
|
position: 0
|
||||||
|
cache_metadata:
|
||||||
|
contexts:
|
||||||
|
- 'languages:language_content'
|
||||||
|
- 'languages:language_interface'
|
||||||
|
- 'user.node_grants:view'
|
||||||
|
- user.permissions
|
||||||
|
max-age: -1
|
||||||
|
tags:
|
||||||
|
- 'config:field.storage.node.body'
|
||||||
page:
|
page:
|
||||||
display_options:
|
display_options:
|
||||||
path: test-feed-display
|
path: test-feed-display
|
||||||
|
display_extenders: { }
|
||||||
display_plugin: page
|
display_plugin: page
|
||||||
display_title: <em>Page</em>
|
display_title: '<em>Page</em>'
|
||||||
id: page
|
id: page
|
||||||
position: 0
|
position: 0
|
||||||
|
cache_metadata:
|
||||||
|
contexts:
|
||||||
|
- 'languages:language_content'
|
||||||
|
- 'languages:language_interface'
|
||||||
|
- url.query_args
|
||||||
|
- 'user.node_grants:view'
|
||||||
|
- user.permissions
|
||||||
|
max-age: -1
|
||||||
|
tags:
|
||||||
|
- 'config:field.storage.node.body'
|
||||||
|
|
|
@ -863,11 +863,14 @@ function template_preprocess_views_view_row_rss(&$variables) {
|
||||||
$variables['title'] = $item->title;
|
$variables['title'] = $item->title;
|
||||||
$variables['link'] = $item->link;
|
$variables['link'] = $item->link;
|
||||||
|
|
||||||
/** @var \Drupal\Core\Render\RendererInterface $renderer */
|
// The description is the only place where we should find HTML.
|
||||||
$renderer = \Drupal::service('renderer');
|
// @see https://validator.w3.org/feed/docs/rss2.html#hrelementsOfLtitemgt
|
||||||
// We render the item description. It might contain entities, which attach rss
|
// If we have a render array, render it here and pass the result to the
|
||||||
// elements via hook_entity_view, see comment_entity_view().
|
// template, letting Twig autoescape it.
|
||||||
$variables['description'] = is_array($item->description) ? $renderer->render($item->description) : $item->description;
|
if (isset($item->description) && is_array($item->description)) {
|
||||||
|
$variables['description'] = (string) \Drupal::service('renderer')->render($item->description);
|
||||||
|
}
|
||||||
|
|
||||||
$variables['item_elements'] = array();
|
$variables['item_elements'] = array();
|
||||||
foreach ($item->elements as $element) {
|
foreach ($item->elements as $element) {
|
||||||
if (isset($element['attributes']) && is_array($element['attributes'])) {
|
if (isset($element['attributes']) && is_array($element['attributes'])) {
|
||||||
|
|
Loading…
Reference in New Issue