diff -u b/core/lib/Drupal/Core/Render/ProtectedRenderArray.php b/core/lib/Drupal/Core/Render/ProtectedRenderArray.php --- b/core/lib/Drupal/Core/Render/ProtectedRenderArray.php +++ b/core/lib/Drupal/Core/Render/ProtectedRenderArray.php @@ -25,6 +25,35 @@ } /** + * Determines if a given array is a render array. + * + * @param mixed $input + * A variable that may be a render array. + * + * @return boolean + * Whether or not the given array is a render array. + */ + public static function isRenderArray($input) { + if (!is_array($input)) { + return FALSE; + } + // Recurse over all keys in the array to determine if any are properties. + // This is done as the render system allows deeply nested arrays that may + // not contain property keys in the first few levels. + $iterator = new \RecursiveArrayIterator($input); + $recursive = new \RecursiveIteratorIterator( + $iterator, + \RecursiveIteratorIterator::SELF_FIRST + ); + foreach ($recursive as $key => $value) { + if (Element::property($key)) { + return TRUE; + } + } + return FALSE; + } + + /** * {@inheritdoc} */ public function toRenderable() { @@ -48,7 +77,7 @@ */ public function offsetGet($index) { $value = parent::offsetGet($index); - if (is_array($value) && !empty($value)) { + if (self::isRenderArray($value)) { $value = new ProtectedRenderArray($value); } return $value; diff -u b/core/lib/Drupal/Core/Render/ProtectedRenderArrayIterator.php b/core/lib/Drupal/Core/Render/ProtectedRenderArrayIterator.php --- b/core/lib/Drupal/Core/Render/ProtectedRenderArrayIterator.php +++ b/core/lib/Drupal/Core/Render/ProtectedRenderArrayIterator.php @@ -19,7 +19,7 @@ */ public function offsetGet($index) { $value = parent::offsetGet($index); - if (is_array($value) && !empty($value)) { + if (ProtectedRenderArray::isRenderArray($value)) { $value = new ProtectedRenderArray($value); } return $value; @@ -30,7 +30,7 @@ */ public function current() { $value = parent::current(); - if (is_array($value) && !empty($value)) { + if (ProtectedRenderArray::isRenderArray($value)) { $value = new ProtectedRenderArray($value); } return $value; diff -u b/core/lib/Drupal/Core/Template/TwigEnvironment.php b/core/lib/Drupal/Core/Template/TwigEnvironment.php --- b/core/lib/Drupal/Core/Template/TwigEnvironment.php +++ b/core/lib/Drupal/Core/Template/TwigEnvironment.php @@ -157,7 +157,7 @@ public function wrapContext(&$context) { if (is_array($context)) { foreach ($context as $key => $value) { - if (is_array($context[$key]) && !empty($context[$key])) { + if (ProtectedRenderArray::isRenderArray($context[$key])) { $context[$key] = new ProtectedRenderArray($context[$key]); } } diff -u b/core/tests/Drupal/Tests/Core/Render/ProtectedRenderArrayTest.php b/core/tests/Drupal/Tests/Core/Render/ProtectedRenderArrayTest.php --- b/core/tests/Drupal/Tests/Core/Render/ProtectedRenderArrayTest.php +++ b/core/tests/Drupal/Tests/Core/Render/ProtectedRenderArrayTest.php @@ -23,6 +23,8 @@ public function testSubArrayAccess(ProtectedRenderArray $protected_array) { $this->assertTrue($protected_array['sub_array'] instanceof ProtectedRenderArray); $this->assertTrue($protected_array['sub_array']['sub_sub_array'] instanceof ProtectedRenderArray); + $this->assertTrue(is_array($protected_array['sub_non_render_array'])); + $this->assertTrue($protected_array['sub_odd_array']['foo']['bar'] instanceof ProtectedRenderArray); } /** @@ -33,9 +35,12 @@ */ public function testIteratedSubArrayAccess(ProtectedRenderArray $protected_array) { foreach ($protected_array as $key => $value) { - if ($key === 'sub_array') { + if ($key === 'sub_array' || $key === 'sub_odd_array') { $this->assertTrue($value instanceof ProtectedRenderArray); } + if ($key === 'sub_non_render_array') { + $this->assertTrue(is_array($value)); + } } } @@ -77,6 +82,20 @@ 'sub_markup' => [ '#markup' => 'Test', ], + 'sub_non_render_array' => [ + 'foo' => 'bar', + 'baz', + ], + // This appears malformed, but is valid to the render system. + 'sub_odd_array' => [ + 'foo' => [ + 'bar' => [ + 'baz' => [ + '#markup' => 'Really, really nested!' + ] + ], + ], + ], ]) ], ];