I don't know what the original use-case/scenario behind this was but currently drupal_render() will not render #markup if #theme is set.
// If #theme was not set, but the element has raw #markup, prepend the content
// in #markup to #children. #children may contain the rendered content
// supplied by #theme, or the rendered child elements, as processed above. If
// both #theme and #markup are set, then #theme is responsible for rendering
// the element. Eventually assigned #theme_wrappers will expect both the
// element's #markup and the rendered content of child elements in #children.
if (!isset($elements['#theme']) && isset($elements['#markup'])) {
$elements['#children'] = $elements['#markup'] . $elements['#children'];
}
This isn't documented anywhere other than in the inline docs.
This would be simpler and easier to understand I believe, and ties in with #2005970: '#type' should be required in renderable arrays and should solely define the behaviour of drupal_render().
// If the element has #markup defining raw HTML prepend #markup to #children.
// At this point #children may contain the content rendered by theme() or
// recursively by drupal_render(). #theme_wrappers will expect a single
// #children value so we do this concatenation now to allow #markup to be
// warpped.
if (isset($elements['#markup'])) {
$elements['#children'] = $elements['#markup'] . $elements['#children'];
}
Example
renderable array A:
array(
'#theme' => 'foo',
'#markup' => 'bar',
);
array B:
array(
'#type' => 'foo',
'#markup' => 'bar,
);
Assuming that element_info() does not define #theme = #type by default for 'foo' (this is what core generally does do but is not guaranteed or required by the current API).
I would expect both arrays to be treated similarly, at least for the purposes of deciding what to do with the #markup.
Renderable array A in HEAD will have its #type set to 'markup' (as #type is not set) but #markup will not be rendered.
Renderable array B in HEAD will have its #type left as 'foo' but #markup will be rendered.
This behaviour seems counter-intuitive to me.
Proposed solution
If #markup is set, unconditionally concatenate it to #children so that regardless of #type or #theme it will always be rendered. This is not to say that the behaviour where #type => 'markup' is set as a default is to change, simply that #markup if set is always rendered in the final output of drupal_render().