diff --git a/core/lib/Drupal/Core/Render/ReadOnlyRenderArray.php b/core/lib/Drupal/Core/Render/ProtectedRenderArray.php
similarity index 85%
rename from core/lib/Drupal/Core/Render/ReadOnlyRenderArray.php
rename to core/lib/Drupal/Core/Render/ProtectedRenderArray.php
index b17a680..7e675c4 100644
--- a/core/lib/Drupal/Core/Render/ReadOnlyRenderArray.php
+++ b/core/lib/Drupal/Core/Render/ProtectedRenderArray.php
@@ -7,10 +7,10 @@
*
* @ingroup utility
*/
-class ReadOnlyRenderArray extends \ArrayObject implements RenderableInterface {
+class ProtectedRenderArray extends \ArrayObject implements RenderableInterface {
/**
- * ReadOnlyRenderArray constructor.
+ * ProtectedRenderArray constructor.
*
* @param array $input
* The render array to wrap into a read-only object.
@@ -32,7 +32,7 @@ public function toRenderable() {
* @param mixed $index
* The index with the value.
*
- * @return \Drupal\Core\Render\ReadOnlyRenderArray|mixed
+ * @return \Drupal\Core\Render\ProtectedRenderArray|mixed
*/
public function __get($index) {
return $this->offsetGet($index);
@@ -44,7 +44,7 @@ public function __get($index) {
public function offsetGet($index) {
$value = parent::offsetGet($index);
if (is_array($value) && !empty($value)) {
- $value = new ReadOnlyRenderArray($value);
+ $value = new ProtectedRenderArray($value);
}
return $value;
}
diff --git a/core/lib/Drupal/Core/Render/RenderArrayIterator.php b/core/lib/Drupal/Core/Render/RenderArrayIterator.php
index 55a4302..e7ffded 100644
--- a/core/lib/Drupal/Core/Render/RenderArrayIterator.php
+++ b/core/lib/Drupal/Core/Render/RenderArrayIterator.php
@@ -15,7 +15,7 @@ class RenderArrayIterator extends \ArrayIterator {
public function offsetGet($index) {
$value = parent::offsetGet($index);
if (is_array($value) && !empty($value)) {
- $value = new ReadOnlyRenderArray($value);
+ $value = new ProtectedRenderArray($value);
}
return $value;
}
@@ -26,7 +26,7 @@ public function offsetGet($index) {
public function current() {
$value = parent::current();
if (is_array($value) && !empty($value)) {
- $value = new ReadOnlyRenderArray($value);
+ $value = new ProtectedRenderArray($value);
}
return $value;
}
diff --git a/core/lib/Drupal/Core/Template/TwigEnvironment.php b/core/lib/Drupal/Core/Template/TwigEnvironment.php
index 584c600..91ddcc1 100644
--- a/core/lib/Drupal/Core/Template/TwigEnvironment.php
+++ b/core/lib/Drupal/Core/Template/TwigEnvironment.php
@@ -4,7 +4,7 @@
use Drupal\Core\Cache\CacheBackendInterface;
use Drupal\Core\Render\Markup;
-use Drupal\Core\Render\ReadOnlyRenderArray;
+use Drupal\Core\Render\ProtectedRenderArray;
use Drupal\Core\State\StateInterface;
/**
@@ -155,7 +155,7 @@ public function wrapContext(&$context) {
if (is_array($context)) {
foreach ($context as $key => $value) {
if (is_array($context[$key]) && !empty($context[$key])) {
- $context[$key] = new ReadOnlyRenderArray($context[$key]);
+ $context[$key] = new ProtectedRenderArray($context[$key]);
}
}
}
@@ -168,12 +168,12 @@ public function wrapContext(&$context) {
* An array of parameters.
*/
public function unWrapContext(&$context) {
- if (is_object($context) && $context instanceof ReadOnlyRenderArray) {
+ if (is_object($context) && $context instanceof ProtectedRenderArray) {
$context = $context->getArrayCopy();
}
if (is_array($context)) {
foreach ($context as $key => $value) {
- if (is_object($context[$key]) && $context[$key] instanceof ReadOnlyRenderArray) {
+ if (is_object($context[$key]) && $context[$key] instanceof ProtectedRenderArray) {
$context[$key] = $context[$key]->getArrayCopy();
}
}
diff --git a/core/lib/Drupal/Core/Template/TwigExtension.php b/core/lib/Drupal/Core/Template/TwigExtension.php
index d0d8779..014c2e3 100644
--- a/core/lib/Drupal/Core/Template/TwigExtension.php
+++ b/core/lib/Drupal/Core/Template/TwigExtension.php
@@ -9,7 +9,7 @@
use Drupal\Core\Render\AttachmentsInterface;
use Drupal\Core\Render\BubbleableMetadata;
use Drupal\Core\Render\Markup;
-use Drupal\Core\Render\ReadOnlyRenderArray;
+use Drupal\Core\Render\ProtectedRenderArray;
use Drupal\Core\Render\RenderableInterface;
use Drupal\Core\Render\RendererInterface;
use Drupal\Core\Routing\UrlGeneratorInterface;
@@ -248,7 +248,7 @@ public function getPath($name, $parameters = [], $options = []) {
* (optional) An associative array of additional options. The 'absolute'
* option is forced to be TRUE.
*
- * @return \Drupal\Core\Render\ReadOnlyRenderArray
+ * @return \Drupal\Core\Render\ProtectedRenderArray
* The generated absolute URL for the given route.
*
* @todo Add an option for scheme-relative URLs.
@@ -261,7 +261,7 @@ public function getUrl($name, $parameters = [], $options = []) {
// Return as render array, so we can bubble the bubbleable metadata.
$build = ['#markup' => $generated_url->getGeneratedUrl()];
$generated_url->applyTo($build);
- return new ReadOnlyRenderArray($build);
+ return new ProtectedRenderArray($build);
}
/**
@@ -274,7 +274,7 @@ public function getUrl($name, $parameters = [], $options = []) {
* @param array|\Drupal\Core\Template\Attribute $attributes
* An optional array or Attribute object of link attributes.
*
- * @return \Drupal\Core\Render\ReadOnlyRenderArray
+ * @return \Drupal\Core\Render\ProtectedRenderArray
* A render array representing a link to the given URL.
*/
public function getLink($text, $url, $attributes = []) {
@@ -301,7 +301,7 @@ public function getLink($text, $url, $attributes = []) {
'#title' => $text,
'#url' => $url,
];
- return new ReadOnlyRenderArray($build);
+ return new ProtectedRenderArray($build);
}
/**
diff --git a/core/modules/forum/forum.module b/core/modules/forum/forum.module
index e0a173a..60391ff 100644
--- a/core/modules/forum/forum.module
+++ b/core/modules/forum/forum.module
@@ -7,9 +7,10 @@
use Drupal\comment\CommentInterface;
use Drupal\comment\Plugin\Field\FieldType\CommentItemInterface;
+use Drupal\Component\Utility\Xss;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Entity\EntityTypeInterface;
-use Drupal\Core\Render\ReadOnlyRenderArray;
+use Drupal\Core\Render\Markup;
use Drupal\Core\Url;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Routing\RouteMatchInterface;
@@ -546,7 +547,9 @@ function template_preprocess_forum_list(&$variables) {
$row = 0;
// Sanitize each forum so that the template can safely print the data.
foreach ($variables['forums'] as $id => $forum) {
- $variables['forums'][$id]->description = new ReadOnlyRenderArray(['#markup' => $forum->description->value]);
+ // Work-around the fact that this is an object instead of a render array
+ // by setting the property to a filtered Markup object so it's not escaped.
+ $variables['forums'][$id]->description = Markup::create(Xss::filter($forum->description->value));
$variables['forums'][$id]->link = forum_uri($forum);
$variables['forums'][$id]->name = $forum->label();
$variables['forums'][$id]->is_container = !empty($forum->forum_container->value);
diff --git a/core/tests/Drupal/Tests/Core/Template/TwigExtensionTest.php b/core/tests/Drupal/Tests/Core/Template/TwigExtensionTest.php
index 49169c4..4024a8a 100644
--- a/core/tests/Drupal/Tests/Core/Template/TwigExtensionTest.php
+++ b/core/tests/Drupal/Tests/Core/Template/TwigExtensionTest.php
@@ -3,7 +3,7 @@
namespace Drupal\Tests\Core\Template;
use Drupal\Core\GeneratedLink;
-use Drupal\Core\Render\ReadOnlyRenderArray;
+use Drupal\Core\Render\ProtectedRenderArray;
use Drupal\Core\Render\RenderableInterface;
use Drupal\Core\StringTranslation\TranslatableMarkup;
use Drupal\Core\Template\Loader\StringLoader;
@@ -219,7 +219,7 @@ public function testSafeJoin() {
$markup->__toString()->willReturn('will be markup');
$markup = $markup->reveal();
- $items = new ReadOnlyRenderArray([
+ $items = new ProtectedRenderArray([
'will be escaped',
$markup,
['#markup' => 'will be rendered'],
@@ -228,7 +228,7 @@ public function testSafeJoin() {
$this->assertEquals('<em>will be escaped</em>
will be markup
will be rendered', $result);
// Ensure safe_join Twig filter supports Traversable variables.
- $items = new ReadOnlyRenderArray([
+ $items = new ProtectedRenderArray([
'will be escaped',
$markup,
['#markup' => 'will be rendered'],