If you use code similar to the following one to define the items shown in a form, in a form builder, the rendered form contains just the markup element; the textfield will not be rendered.

  $form['html'] = array(
    '#type' => 'markup',
    '#markup' => '<h2>My Heading</h2>',
    '#tree' => true,
  );

  $form['html']['element'] = array(
    '#type' => 'textfield',
    '#title' => 'Foo',
  );

The reference page for the "markup" element reports the "#tree" property as supported by the "#markup" element. The expected result would be that the child items of that element are rendered too.

CommentFileSizeAuthor
#5 RSS feed | Drupal.png51.87 KBavpaderno

Comments

darrell_ulm’s picture

Status: Active » Closed (works as designed)

This appears fixed.

Was drupal_render() used in the above example? I think the docs mention that #markup is meant to be used within fieldsets.

Here is a test I ran, which is a slight modification of yours, and the #tree and it appears to work with a field set. However, perhaps this is the way that #tree was meant to work so it could be used without field sets.

The test:

<?php
  $form['html'] = array(
    '#type' => 'fieldset',
    '#title' => t('TEST'),
    '#collapsible' => FALSE,
    '#tree' => TRUE,
  );
  $form['html']['mark'] = array(
    '#type' => 'markup',
    '#markup' => '<h2>My Heading</h2>',
  );
  $form['html']['mark2'] = array(
    '#type' => 'markup',
    '#markup' => '<h3>Next Heading</h3>',
  );
  $form['html']['element'] = array(
    '#type' => 'textfield',
    '#title' => 'Foo',
  );
print drupal_render($form);
?>

Also from the Drupal online manual see:
http://drupal.org/node/751826
http://drupal.org/node/48643
http://api.drupal.org/api/drupal/developer--topics--forms_api_reference....
http://api.drupal.org/api/drupal/developer--topics--forms_api_reference....

Also:

An important thing to note: notice that $form['access'] has a '#tree' => TRUE attribute. this setting retains the full tree structure for all elements under it when it is passed to $form_state['values']. you must explicitly declare this anywhere you wish to retain an array's full hierarchy when it is passed.

  $form['access'] = array(
    '#type' => 'fieldset',
    '#title' => t('Access log settings'),
    '#tree' => TRUE,
  );

Hope that solves it.

bleen’s picture

Status: Closed (works as designed) » Active

@darellulm .. your small change to the example in the original post is a fundamental one. kiamlaluno's whole point is that an element of #type = markup should obey #tree just like any other element. Your example shows that #tree is working for #type = fieldset, but that is not the issue being raised here.

darrell_ulm’s picture

Title: Children of "#markup" form element are not rendered » "#tree" used with a "#markup" element causes the child items not to be rendered
Version: 7.x-dev » 8.x-dev

Right I see that. I wonder if the intent is that #tree should only work with fieldsets or it should be able to work with anything. Assuming now it is supposed to work with other, ?any?, element types.

bleen’s picture

#tree definitely works with other element types that are not fieldsets...

avpaderno’s picture

StatusFileSize
new51.87 KB

Just to make clear to what I am referring, I created a test module containing the following code:

/**
 * Implements hook_menu().
 */
function code_testing_menu() {
  $items = array();
  
  $items["test/form/markup"] = array(
    'title' => 'RSS feed', 
    'page callback' => 'drupal_get_form',
    'page arguments' => array('code_testing_markup_form'), 
    'access arguments' => array('access content'), 
    'type' => MENU_CALLBACK,
  );
  
  return $items;
}

/**
 * Form builder.
 */
function code_testing_markup_form($form, &$form_state) {
  $form['html'] = array(
    '#type' => 'markup',
    '#markup' => '<h2>My Heading</h2>',
    '#tree' => true,
  );

  $form['html']['element'] = array(
    '#type' => 'textfield',
    '#title' => 'Test',
  );
  
  return $form;
}  

When I visit the page it defines, this is what I see, in Drupal 8.

screenshot

#markup is not supposed to be used only inside field sets, nor is the #tree property supposed not to be used within #markup, as bleen18 already said.

darrell_ulm’s picture

True enough.

And a test I ran:

$form['testme'] = array(
    '#type' => 'textarea',
    '#title' => 'the test title',
    '#value' => 'TextValue',
    '#tree' => TRUE,
  );
  $form['testme']['element'] = array(
    '#type' => 'textfield',
    '#title' => 'Test textfield title',
  );

And it shows:

the test title
[TextValue]

It does not show the second element.

Also:

$form['status'] = array(
  '#type' =>'checkbox', 
  '#title' => t('I am checkbox 1'),
  '#tree' => TRUE,
);
$form['status']['elem'] = array(
  '#type' =>'checkbox', 
  '#title' => t('I am checkbox 2'),
  );

Shows only:

[ ] I am checkbox 1

So it would seem these non fieldset elements are acting similar.

valthebald’s picture

Status: Active » Closed (works as designed)

#tree is not intended to tell Forms API that element has children. I.e. with the last 8.x, both

  $form['parent'] = array(
    '#type' => 'markup',
    '#markup' => '<h2>Parent</h2>',
    '#tree' => TRUE,
  );
  $form['parent']['child'] = array(
    '#type' => 'checkbox', 
    '#title' => t('I am child'));

and

  $form['parent'] = array(
    '#type' => 'markup',
    '#markup' => '<h2>Parent</h2>',
  );
  $form['parent']['child'] = array(
    '#type' => 'checkbox', 
    '#title' => t('I am a child'));

have the same effect: checkbox titled I am a child appears on form.
For the reference, please check http://drupal.org/node/48643

Kazanir’s picture

Title: "#tree" used with a "#markup" element causes the child items not to be rendered » Children of "#markup" form element are not rendered
Version: 8.x-dev » 7.x-dev
Status: Closed (works as designed) » Active

In that case, this is an outstanding bug in D7. I have just tested it with the following code:

  $form['event_information'] = array(
    '#type' => 'markup',
    '#markup' => '<div><h3>Event Information</h3></div>',
  );
  $form['event_information']['info_1'] = array(
    '#type' => 'markup',
    '#markup' => '<div>' . $information_1_var . '</div>',
  );

Only the first form element here prints -- its child element is not rendered.

valthebald’s picture

Title: "#tree" used with a "#markup" element causes the child items not to be rendered » Children of "#markup" form element are not rendered
Version: 8.x-dev » 7.x-dev

tldr: fix is non-trivial for D7, should be won't fixed
In detail:
in function drupal_render(common.inc):

  // Make any final changes to the element before it is rendered. This means
  // that the $element or the children can be altered or corrected before the
  // element is rendered into the final text.
  if (isset($elements['#pre_render'])) {
    foreach ($elements['#pre_render'] as $function) {
      if (function_exists($function)) {
        $elements = $function($elements);
      }
    }
  }
  ...
  if ($elements['#children'] == '') {
    foreach ($children as $key) {
      $elements['#children'] .= drupal_render($elements[$key]);
    }
  }

#markup elements have pre_render function drupal_pre_render_markup(), that copies $element['#markup'] to $elements['#children']. Existing $elements['#children'] prevents children from being rendered. Bingo!
It is possible to try and fix the current behavior and, for example, use #theme_wrappers instead of #pre_render technique for markup elements. That's how fieldset elements are being rendered.
I think the reason for the current behavior is simple - speed. And seriously - use case of #markup element having children sounds too specific to shake rendering basics.

avpaderno’s picture

@valthebald I am fine with that, but in that case what shown in this page should be changed, since it shows that the only form element that doesn't use #tree is value. Basing on your explanation, that is not true.

Kazanir’s picture

This isn't really what #tree is for, but the documentation should clearly indicate that this is the case then.

valthebald’s picture

Title: Children of "#markup" form element are not rendered » Document that #tree property has no effect on #markup elements
Component: forms system » documentation

Changing topic and component. (should this be moved to another queue? webmasters or something?)

bleen’s picture

Category: bug » task
Issue tags: +Needs documentation

... I think valthebald fell asleep on his keyboard :)

jhodgdon’s picture

Project: Drupal core » Documentation
Version: 7.x-dev »
Component: documentation » API documentation files
Issue tags: -Needs documentation +FAPI reference

OK... There are really a couple of different things going on here:

a) Several of the comments above illustrate a common misunderstanding of what #tree does. #tree affects how the values are passed to validate/submit functions in $form_state -- whether they are given to you in a flat array or a hierarchical array. #tree does not affect how the form is presented on the page in any way.

b) Another misunderstanding is about whether you can nest form elements inside other form elements in a $form array. You cannot do that in general (at least in Drupal 7) -- you can only do that for elements that support nesting, such as fieldsets and vertical tabs. Markup elements do not support nesting, as noted above.

So... Since both of these misunderstandings have come up, probably some documentation needs to be improved:

1. The Form API reference #tree section should explain what #tree does. Currently it's totally useless, and to make matters worse, it points to an obsolete archived page for more information. So that needs to be fixed.
https://api.drupal.org/api/drupal/developer!topics!forms_api_reference.h...
The Form API reference is in the Documentation git repository, so I'm moving this issue there.

2. The "more information" link there should go to the Quickstart guide, which says it is for Drupal 6 but really applies to both 6 and 7:
https://drupal.org/node/751826

3. That quickstart guide should explain the difference between having a fieldset with #tree being TRUE and one with #tree being FALSE (the effect on the values array), so that people have some hope of not being confused about #tree.

4. And maybe it should explain that you can't nest arbitrary form elements, just ones that support nesting.

star-szr’s picture

star-szr’s picture

Issue summary: View changes

Made the report clearer.

solideogloria’s picture

Issue summary: View changes

The documentation is still unhelpful. Have any documentation changes been made for this?

There is nothing in the docs about which elements support nesting, either.

quietone’s picture

Status: Active » Closed (won't fix)

This is for the Drupal 7 Form API reference, so this is now a won't fix.

quietone’s picture

avpaderno’s picture