The docs state that theme hooks are "responsible" for rendering child elements in render arrays.

  // Call the element's #theme function if it is set. Then any children of the
  // element have to be rendered there. If the internal #render_children
  // property is set, do not call the #theme function to prevent infinite
  // recursion.

In some cases, the hooks kind of "cheat" by calling drupal_render() in their preprocess functions, hence the need for #render_children in drupal_render(), but at least the job gets done.

More worryingly, however, there are theme functions and templates that do *not* render the child elements at all, but *do* invent their own attributes that look suspiciously like awkward placeholders for where the rendered children should go.

Take #theme 'maintenance_page' for example, it has two variables defined in the theme registry, 'content' and 'show_messages'.

This means that if we build a renderable array like this:

$maintenance_page = array(
  '#theme' => 'maintenance_page',
  '#content' => 'foo',
  'child' => array('#markup' => 'bar'),
);
print $maintenance_page;

We get back a maintenance page with the "content" of foo, but bar is not rendered. So, two concerns here:

- Why have we invented #content when the concept of "child elements" already exists in the render API?
- Why does this theme hook not handle rendering children, something the docs explicitly state theme hooks that are not #theme_wrappers are required to do?

There are *lots* of theme hooks in core that define a "content" variable or equivalent. I'm sure this is for historical reasons, but it now appears to be at best very "crufty" and at worse a bug.

To make matters worse, the way that many theme hooks are implemented actually makes it impossible for them to "be responsible for" rendering child elements as theme() strips the child elements out of the $variables array that is passed to the preprocess and theme function/templates unless 'render element' is set:

 // If a renderable array is passed as $variables, then set $variables to
  // the arguments expected by the theme function.
  if (isset($variables['#theme']) || isset($variables['#theme_wrappers'])) {
    $element = $variables;
    $variables = array();
    if (isset($info['variables'])) {
      foreach (array_keys($info['variables']) as $name) {
        if (isset($element["#$name"]) || array_key_exists("#$name", $element)) {
          $variables[$name] = $element["#$name"];
        }
      }
    }
    else {
      $variables[$info['render element']] = $element;
      // Give a hint to render engines to prevent infinite recursion.
      $variables[$info['render element']]['#render_children'] = TRUE;
    }
  }

Comments

Eric_A’s picture

The whole inline comment is about theme hooks that handle a render element as their only argument. Not about hooks that handle variables.

- Why does this theme hook not handle rendering children, something the docs explicitly state theme hooks that are not #theme_wrappers are required to do?

theme_maintenance() handles variables, not a render element.
Every theme hook just handles what it is designed to handle. Hooks that handle elements can handle child elements. Hooks that handle variables handle the variables they are designed to handle. Which can never be an element child. Because these hooks do not handle elements.
The theme() function transforms a render element to a variables array for hooks that handle variables by mapping element properties to variables. That's all. It cannot map a child element to a variable.

thedavidmeister’s picture

#1 - Yes, that seems like a fairly accurate assessment of the situation, but I can't tell if you're describing the nature of the bug further, or trying to explain that somehow this behaviour is a "good thing" or "working as designed".

thedavidmeister’s picture

The whole inline comment is about theme hooks that handle a render element as their only argument. Not about hooks that handle variables.

The comment doesn't make this clear at all. Nor is there a clear explanation on how to support nested data structures in the render API where child elements are compatible with theme hooks that use variables instead of 'render element'.

sun’s picture

thedavidmeister’s picture

Category: Task » Bug report

So, would a potential way forward here to merge the concept of #theme_wrappers and #theme into a single thing?

The proposal would be:

- One attribute #theme that behaves as #theme_wrappers currently does
- Remove any variables that currently exist in theme functions/templates for the sole purpose of working around the fact that children cannot be rendered, and replace them with the functionality that already exists for #theme_wrappers, i.e. concatenate/print $element['#children']

It's obvious to me what we gain by merging the concepts: A unified set of rules and expectations for every theme hook

It's not obvious what we lose by merging the concepts (other than a bit of time re-jigging some templates and documenting the API change), so I'd love to hear what other people think.

Version: 8.0.x-dev » 8.1.x-dev

Drupal 8.0.6 was released on April 6 and is the final bugfix release for the Drupal 8.0.x series. Drupal 8.0.x will not receive any further development aside from security fixes. Drupal 8.1.0-rc1 is now available and sites should prepare to update to 8.1.0.

Bug reports should be targeted against the 8.1.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.2.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.1.x-dev » 8.2.x-dev

Drupal 8.1.9 was released on September 7 and is the final bugfix release for the Drupal 8.1.x series. Drupal 8.1.x will not receive any further development aside from security fixes. Drupal 8.2.0-rc1 is now available and sites should prepare to upgrade to 8.2.0.

Bug reports should be targeted against the 8.2.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.3.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

joelpittet’s picture

Version: 8.2.x-dev » 9.x-dev
Status: Active » Postponed

I'd love to discuss this idea further, a snippet of one conversion would be great as a discussion point. Rendering the children in the template without them being flattened earlier than {{ children }} would be ideal or even

{% for child in children %}
  {{ child }}
{% endfor %}

But the ship may have sailed for this in 8.x unless there is some additions we can make to make this easier a template?
Let's revisit in 9.x unless there is a proposal for BC in 8.x? Likely won't convert existing render element for sure but help new elements.

catch’s picture

Version: 9.x-dev » 8.3.x-dev
Status: Postponed » Active

Let's keep this against 8.x until we've exhausted the potential for a bc layer.

Version: 8.3.x-dev » 8.4.x-dev

Drupal 8.3.0-alpha1 will be released the week of January 30, 2017, which means new developments and disruptive changes should now be targeted against the 8.4.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.4.x-dev » 8.5.x-dev

Drupal 8.4.0-alpha1 will be released the week of July 31, 2017, which means new developments and disruptive changes should now be targeted against the 8.5.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.5.x-dev » 8.6.x-dev

Drupal 8.5.0-alpha1 will be released the week of January 17, 2018, which means new developments and disruptive changes should now be targeted against the 8.6.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.6.x-dev » 8.7.x-dev

Drupal 8.6.0-alpha1 will be released the week of July 16, 2018, which means new developments and disruptive changes should now be targeted against the 8.7.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.7.x-dev » 8.8.x-dev

Drupal 8.7.0-alpha1 will be released the week of March 11, 2019, which means new developments and disruptive changes should now be targeted against the 8.8.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.8.x-dev » 8.9.x-dev

Drupal 8.8.0-alpha1 will be released the week of October 14th, 2019, which means new developments and disruptive changes should now be targeted against the 8.9.x-dev branch. (Any changes to 8.9.x will also be committed to 9.0.x in preparation for Drupal 9’s release, but some changes like significant feature additions will be deferred to 9.1.x.). For more information see the Drupal 8 and 9 minor version schedule and the Allowed changes during the Drupal 8 and 9 release cycles.

Version: 8.9.x-dev » 9.1.x-dev

Drupal 8.9.0-beta1 was released on March 20, 2020. 8.9.x is the final, long-term support (LTS) minor release of Drupal 8, which means new developments and disruptive changes should now be targeted against the 9.1.x-dev branch. For more information see the Drupal 8 and 9 minor version schedule and the Allowed changes during the Drupal 8 and 9 release cycles.

Version: 9.1.x-dev » 9.2.x-dev

Drupal 9.1.0-alpha1 will be released the week of October 19, 2020, which means new developments and disruptive changes should now be targeted for the 9.2.x-dev branch. For more information see the Drupal 9 minor version schedule and the Allowed changes during the Drupal 9 release cycle.

Version: 9.2.x-dev » 9.3.x-dev

Drupal 9.2.0-alpha1 will be released the week of May 3, 2021, which means new developments and disruptive changes should now be targeted for the 9.3.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 9.3.x-dev » 9.4.x-dev

Drupal 9.3.0-rc1 was released on November 26, 2021, which means new developments and disruptive changes should now be targeted for the 9.4.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 9.4.x-dev » 9.5.x-dev

Drupal 9.4.0-alpha1 was released on May 6, 2022, which means new developments and disruptive changes should now be targeted for the 9.5.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 9.5.x-dev » 10.1.x-dev

Drupal 9.5.0-beta2 and Drupal 10.0.0-beta2 were released on September 29, 2022, which means new developments and disruptive changes should now be targeted for the 10.1.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 10.1.x-dev » 11.x-dev

Drupal core is moving towards using a “main” branch. As an interim step, a new 11.x branch has been opened, as Drupal.org infrastructure cannot currently fully support a branch named main. New developments and disruptive changes should now be targeted for the 11.x branch, which currently accepts only minor-version allowed changes. For more information, see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

darvanen’s picture

Status: Active » Postponed (maintainer needs more info)
Issue tags: +Bug Smash Initiative

This ticket came up as a triage target for the Bug Smash Initiative (find us at #bugsmash on Drupal Slack).

I discussed with @dww. Following the (closed) parent issue link: #2004872: [meta] Theme system architecture changes yields a new direction:

So we think this one might be outdated.

I'm going to mark this PMNMI to give time for feedback. If there is no further activity for three months this ticket may be closed as outdated.

geek-merlin’s picture

Status: Postponed (maintainer needs more info) » Active

@darvanen #23: Thanks for re-triaging this and cross-linking the other issues!

The cross-linked issues are about the wide area of OO-modernizing and pluginifying the theme system, but unfortunately look quite stale with relevant discussion 5 years old.
This issue otoh is clearly about handling render array childen, which is orthogonal to the other issues, and as much a point as when it was created..

So no, imho not outdated nor lacking info.