Definition

drupal_render(&$elements)
drupal/includes/common.inc, line 3741

Description

Renders HTML given a structured array tree.

Recursively iterates over each of the array elements, generating HTML code.

HTML generation is controlled by two properties containing theme functions, #theme and #theme_wrapper.

#theme is the theme function called first. If it is set and the element has any children, they have to be rendered there. For elements that are not allowed to have any children, e.g. buttons or textfields, it can be used to render the element itself. If #theme is not present and the element has children, they are rendered and concatenated into a string by drupal_render_children().

The theme function in #theme_wrapper will be called after #theme has run. It can be used to add further markup around the rendered children, e.g. fieldsets add the required markup for a fieldset around their rendered child elements. A wrapper theme function always has to include the element's #children property in its output, as this contains the rendered children.

For example, for the form element type, by default only the #theme_wrapper property is set, which adds the form markup around the rendered child elements of the form. This allows you to set the #theme property on a specific form to a custom theme function, giving you complete control over the placement of the form's children while not at all having to deal with the form markup itself.

This function is usually called from within a another function, like drupal_get_form() or a theme function. Elements are sorted internally using uasort(). Since this is expensive, when passing already sorted elements to drupal_render(), for example from a database query, set $elements['#sorted'] = TRUE to avoid sorting them a second time.

Parameters

$elements The structured array describing the data to be rendered.

Return value

The rendered HTML.

Related topics

Namesort iconDescription
Input validationFunctions to validate user input.

Code

function drupal_render(&$elements) {
  // Early-return nothing if user does not have access.
  if (!isset($elements) || (isset($elements['#access']) && !$elements['#access'])) {
    return;
  }

  // Do not print elements twice.
  if (isset($elements['#printed']) && $elements['#printed']) {
    return;
  }

  // If the default values for this element have not been loaded yet, populate
  // them.
  if (isset($elements['#type']) && empty($elements['#defaults_loaded'])) {
    $elements += element_info($elements['#type']);
  }
  else {
    $elements += element_basic_defaults();
  }

  // If #markup is not empty and no theme function is set, use theme_markup.
  // This allows to specify just #markup on an element without setting the #type.
  if (!empty($elements['#markup']) && empty($elements['#theme'])) {
    $elements['#theme'] = 'markup';
  }

  // 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 (drupal_function_exists($function)) {
        $elements = $function($elements);
      }
    }
  }

  // Get the children of the element, sorted by weight.
  $children = element_children($elements, TRUE);

  $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'])) {
    $elements['#children'] = theme($elements['#theme'], $elements);
  }
  // If #theme was not set and the element has children, render them now
  // using drupal_render_children().
  if ($elements['#children'] == '') {
    $elements['#children'] = drupal_render_children($elements, $children);
  }

  // Let the theme function in #theme_wrapper add markup around the rendered
  // children.
  if (!empty($elements['#theme_wrapper'])) {
    $elements['#children'] = theme($elements['#theme_wrapper'], $elements);
  }

  // Filter the outputted content and make any last changes before the
  // content is sent to the browser. The changes are made on $content
  // which allows the output'ed text to be filtered.
  if (isset($elements['#post_render'])) {
    foreach ($elements['#post_render'] as $function) {
      if (drupal_function_exists($function)) {
        $elements['#children'] = $function($elements['#children'], $elements);
      }
    }
  }
  
    // Add additional CSS and JavaScript files associated with this element.
  foreach (array('css', 'js') as $kind) {
    if (!empty($elements['#attached_' . $kind]) && is_array($elements['#attached_' . $kind])) {
      foreach ($elements['#attached_' . $kind] as $data => $options) {
        // If the value is not an array, it's a filename and passed as first
        // (and only) argument.
        if (!is_array($options)) {
          $data = $options;
          $options = NULL;
        }
        // When drupal_add_js with 'type' => 'setting' is called, the first
        // parameter ($data) is an array. Arrays can't be keys in PHP, so we
        // have to get $data from the value array.
        if (is_numeric($data)) {
          $data = $options['data'];
          unset($options['data']);
        }
        call_user_func('drupal_add_' . $kind, $data, $options);
      }
    }
  }

  $prefix = isset($elements['#prefix']) ? $elements['#prefix'] : '';
  $suffix = isset($elements['#suffix']) ? $elements['#suffix'] : '';

  $elements['#printed'] = TRUE;
  return $prefix . $elements['#children'] . $suffix;
}