Commit 3b1f85aa authored by alexpott's avatar alexpott

Issue #1920886 by Cottser, Fabianx: Drupal_render() should only render the...

Issue #1920886 by Cottser, Fabianx: Drupal_render() should only render the child elements when rendering a 'render element' for the first time.
parent 340a4342
......@@ -5233,8 +5233,10 @@ function drupal_render(&$elements) {
$elements['#children'] = '';
}
// Call the element's #theme function if it is set. Then any children of the
// element have to be rendered there.
if (isset($elements['#theme'])) {
// element have to be rendered there. If the internal #render_children
// property is set, do not call the #theme function to prevent infinite
// recursion.
if (isset($elements['#theme']) && !isset($elements['#render_children'])) {
$elements['#children'] = theme($elements['#theme'], $elements);
}
// If #theme was not set and the element has children, render them now.
......@@ -5272,7 +5274,9 @@ function drupal_render(&$elements) {
// the #type 'page' render array from drupal_render_page() would render the
// $page and wrap it into the html.tpl.php template without the attached
// assets otherwise.
if (isset($elements['#theme_wrappers'])) {
// If the internal #render_children property is set, do not call the
// #theme_wrappers function(s) to prevent infinite recursion.
if (isset($elements['#theme_wrappers']) && !isset($elements['#render_children'])) {
foreach ($elements['#theme_wrappers'] as $theme_wrapper) {
$elements['#children'] = theme($theme_wrapper, $elements);
}
......
......@@ -1036,6 +1036,8 @@ function theme($hook, $variables = array()) {
}
else {
$variables[$info['render element']] = $element;
// Give a hint to render engines to prevent infinite recursion.
$variables[$info['render element']]['#render_children'] = TRUE;
}
}
......
......@@ -193,6 +193,27 @@ function testRegistryRebuild() {
$this->assertIdentical(theme('theme_test_foo', array('foo' => 'c')), 'c', 'The theme registry contains theme_test_foo again after re-enabling the module.');
}
/**
* Tests child element rendering for 'render element' theme hooks.
*/
function testDrupalRenderChildren() {
$element = array(
'#theme' => 'theme_test_render_element_children',
'child' => array(
'#markup' => 'Foo',
),
);
$this->assertIdentical(theme('theme_test_render_element_children', $element), 'Foo', 'drupal_render() avoids #theme recursion loop when rendering a render element.');
$element = array(
'#theme_wrappers' => array('theme_test_render_element_children'),
'child' => array(
'#markup' => 'Foo',
),
);
$this->assertIdentical(theme('theme_test_render_element_children', $element), 'Foo', 'drupal_render() avoids #theme_wrappers recursion loop when rendering a render element.');
}
/**
* Tests theme can provide classes.
*/
......
......@@ -17,6 +17,9 @@ function theme_test_theme($existing, $type, $theme, $path) {
$items['theme_test_foo'] = array(
'variables' => array('foo' => NULL),
);
$items['theme_test_render_element_children'] = array(
'render element' => 'element',
);
return $items;
}
......@@ -172,3 +175,17 @@ function theme_theme_test_foo($variables) {
return $variables['foo'];
}
/**
* Theme function for testing rendering of child elements via drupal_render().
*
* Theme hooks defining a 'render element' add an internal '#render_children'
* property. When this property is found, drupal_render() avoids calling theme()
* on the top-level element to prevent infinite recursion.
*
* @param array $variables
* An associative array containing:
* - element: An associative array containing the properties of the element.
*/
function theme_theme_test_render_element_children($variables) {
return drupal_render($variables['element']);
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment