The Definitive Guide to Drupal 7

How Form Markup is Generated

Forms are generated by modules. The simple function shown in Listing 16–24 is all that is required to generate form markup. It looks really easy, doesn’t it? It is. Of course, there is more to the process to make it functional, such as validating the form and saving the submitted values, but the rest is not your concern in the theme layer. What’s important to you is the structure of a form and how it’s transformed from the $form array to actual markup.

Listing 16-24. A simple unsubscribe form
  1. <?php
  2. function exampleform_unsubscribe(&$form, $form_state) {
  3. $form['email'] = array(
  4. '#type' => 'textfield',
  5. '#title' => t('E-mail address'),
  6. '#required' => TRUE,
  7. );
  8. $form['submit'] = array(
  9. '#type' => 'submit',
  10. '#value' => t('Remove me!'),
  11. );
  12. return $form;
  13. }

In Listing 16–24, you define a very simple form with two elements: a textfield for the e-mail address and a submit button. When rendered, the result looks like those in Figure 16–5. The resulting markup is shown in Listing 16–25.

Screenshot of rendered unsubscribe form
Listing 16-5. Rendered form based on the code from Listing 16–24
Listing 16-25. The markup generated by Drupal for the exampleform_unsubscribe() form in Listing 16–24
  1. <form action="/example/unsubscribe" method="post" id="exampleform-unsubscribe" accept-charset="UTF-8">
  2. <div>
  3. <div class="form-item form-type-textfield form-item-email">
  4. <label for="edit-email">E-mail address <span class="form-required" title="This field is required.">*</span></label>
  5. <input type="text" id="edit-email" name="email" value="" size="60" maxlength="128" class="form-text required" />
  6. </div>
  7. <input type="submit" id="edit-submit" name="op" value="Remove me!" class="form-submit" /> <input type="hidden" name="form_build_id" value="formjKkl1KLWJLnv0hM4DSVd8-40boTgBQAzWWhUn44c15Q" />
  8. <input type="hidden" name="form_token" value="LB07DqsDXK9idWdOHLxUen7jKxm52JqTyHiR7-pNumA" />
  9. <input type="hidden" name="form_id" value="exampleform_unsubscribe" />
  10. </div>
  11. </form>

Form API Elements and Default Properties

In the exampleform_unsubscribe() form, you’ve defined two form elements: the e-mail address and the submit element. The e-mail element’s #type property is textfield, which provides a single line text input. The submit element’s #type is submit, which is the Form API equivalent of <input type="submit" />.

If you look closely at the generated markup in Listing 16–25, you’ll see that you only set two properties in each element, but your markup ended up with some additional attributes. This is because Drupal assigns a default set of properties to each element. In this case, you are using form, textfield, and submit elements, which are defined in system_element_info(), as shown in Listing 16–26. When the form is processed, Drupal merges the properties defined in the form with the default properties.

Listing 16-26. Default element properties as defined in system_element_info() for textfield and submit elements
  1. <?php
  2. $types['form'] = array(
  3. '#method' => 'post',
  4. '#action' => request_uri(), '#theme_wrappers' => array('form'),
  5. );
  6. $types['textfield'] = array(
  7. '#input' => TRUE,
  8. '#size' => 60,
  9. '#maxlength' => 128,
  10. '#autocomplete_path' => FALSE,
  11. '#process' => array('ajax_process_form'), '#theme' => 'textfield',
  12. '#theme_wrappers' => array('form_element'),
  13. );
  14. $types['submit'] = array(
  15. '#input' => TRUE,
  16. '#name' => 'op',
  17. '#button_type' => 'submit',
  18. '#executes_submit_callback' => TRUE,
  19. '#limit_validation_errors' => FALSE,
  20. '#process' => array('ajax_process_form'),
  21. '#theme_wrappers' => array('button'),
  22. );

Rendering of Form Elements

The element properties contain critical information required to render them. Of these properties, two are very important in the theme layer: #theme and #theme_wrappers. When it’s time to render the form, these properties tell Drupal which theme functions to use. There’s also the option to use the #pre_render property to define a function(s) that should run prior to rendering.

#theme
Specifies the theme function to use when rendering the element.
#theme_wrappers
Specifies a theme function or functions that should be used to wrap the rendered children of the element.

To illustrate this process, let’s use the $form['email'] field from the previous form and walk through the process:

  1. theme('textfield', array('element' => $form['email'])) is called. This results in the following markup:

    1. <input type="text" id="edit-email" name="email" value="" size="60" maxlength="128" class="form-text required" />
  2. theme('form_element', array('element' => $form['email'])) is called. This results in the following markup:

    1. <div class="form-item form-type-textfield form-item-email">
    2. <label for="edit-email">E-mail address <span class="form-required" title="This field is required.">*</span> </label>
    3. <input type="text" id="edit-email" name="email" value="" size="60" maxlength="128" class="form-text required" />
    4. <!-- RESULT OF THE RENDERED TEXTFIELD -->
    5. </div>
  3. Finally, after all of the form elements are rendered, the form itself is run through theme_form(), which is specified as the #theme_wrappers in the form element. The theme_form() function takes care of generating the rest of the form markup, including the hidden elements form_build_id, form_token, and form_id.

You are reading content from two chapters on Theme Development from The Definitive Guide to Drupal 7, written by Jacine Luisi and published by Apress on July 19, 2011. All rights reserved.