1 common.inc backdrop_render(&$elements)

Renders HTML given a structured array tree.

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

Renderable arrays have two kinds of key/value pairs: properties and children. Properties have keys starting with '#' and their values influence how the array will be rendered. Children are all elements whose keys do not start with a '#'. Their values should be renderable arrays themselves, which will be rendered during the rendering of the parent array. The markup provided by the children is typically inserted into the markup generated by the parent array.

HTML generation for a renderable array, and the treatment of any children, is controlled by two properties containing theme functions, #theme and #theme_wrappers.

#theme is the theme function called first. If it is set and the element has any children, it is the responsibility of the theme function to render these children. For elements that are not allowed to have any children, e.g. buttons or textfields, the theme function can be used to render the element itself. If #theme is not present and the element has children, each child is itself rendered by a call to backdrop_render(), and the results are concatenated.

The #theme_wrappers property contains an array of theme functions which will be called, in order, after #theme has run. These 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. All wrapper theme functions have to include the element's #children property in their output, as it contains the output of the previous theme functions and the rendered children.

For example, for the form element type, by default only the #theme_wrappers 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.

backdrop_render() can optionally cache the rendered output of elements to improve performance. To use backdrop_render() caching, set the element's #cache property to an associative array with one or several of the following keys:

  • 'keys': An array of one or more keys that identify the element. If 'keys' is set, the cache ID is created automatically from these keys. See backdrop_render_cid_create().
  • 'granularity' (optional): Define the cache granularity using binary combinations of the cache granularity constants, e.g. BACKDROP_CACHE_PER_USER to cache for each user separately or BACKDROP_CACHE_PER_PAGE | BACKDROP_CACHE_PER_ROLE to cache separately for each page and role. If not specified the element is cached globally for each theme and language.
  • 'cid': Specify the cache ID directly. Either 'keys' or 'cid' is required. If 'cid' is set, 'keys' and 'granularity' are ignored. Use only if you have special requirements.
  • 'expire': Set to one of the cache lifetime constants.
  • 'bin': Specify a cache bin to cache the element in. Defaults to 'cache'.

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

backdrop_render() flags each element with a '#printed' status to indicate that the element has been rendered, which allows individual elements of a given array to be rendered independently and prevents them from being rendered more than once on subsequent calls to backdrop_render() (e.g., as part of a larger array). If the same array or element is passed more than once to backdrop_render(), every use beyond the first will return an empty string.

Parameters

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

Return value

string: The rendered HTML.

File

core/includes/common.inc, line 6697
Common functions that many Backdrop modules will need to reference.

Code

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

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

  // Try to fetch the element's markup from cache and return.
  if (isset($elements['#cache'])) {
    $cached_output = backdrop_render_cache_get($elements);
    if ($cached_output !== FALSE) {
      return $cached_output;
    }
  }

  // If #markup is set, ensure #type is set. This allows to specify just #markup
  // on an element without setting #type.
  if (isset($elements['#markup']) && !isset($elements['#type'])) {
    $elements['#type'] = 'markup';
  }

  // 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']);
  }

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

  // Allow #pre_render to abort rendering.
  if (!empty($elements['#printed'])) {
    return '';
  }

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

  // Initialize this element's #children, unless a #pre_render callback already
  // preset #children.
  if (!isset($elements['#children'])) {
    $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.
  // This is the same process as backdrop_render_children() but is inlined
  // for speed.
  if ($elements['#children'] == '') {
    foreach ($children as $key) {
      $elements['#children'] .= backdrop_render($elements[$key]);
    }
  }

  // Let the theme functions in #theme_wrappers add markup around the rendered
  // children.
  if (isset($elements['#theme_wrappers'])) {
    foreach ($elements['#theme_wrappers'] as $theme_wrapper) {
      $elements['#children'] = theme($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) {
      $elements['#children'] = $function($elements['#children'], $elements);
    }
  }

  // Add any JavaScript state information associated with the element.
  if (!empty($elements['#states'])) {
    backdrop_process_states($elements);
  }

  // Add additional libraries, CSS, JavaScript an other custom
  // attached data associated with this element.
  if (!empty($elements['#attached'])) {
    backdrop_process_attached($elements);
  }

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

  // Cache the processed element if #cache is set.
  if (isset($elements['#cache'])) {
    backdrop_render_cache_set($output, $elements);
  }

  $elements['#printed'] = TRUE;
  return $output;
}