You are here

function drupal_pre_render_links in Zircon Profile 8

Same name and namespace in other branches
  1. 8.0 core/includes/common.inc \drupal_pre_render_links()

Pre-render callback: Collects child links into a single array.

This function can be added as a pre_render callback for a renderable array, usually one which will be themed by links.html.twig. It iterates through all unrendered children of the element, collects any #links properties it finds, merges them into the parent element's #links array, and prevents those children from being rendered separately.

The purpose of this is to allow links to be logically grouped into related categories, so that each child group can be rendered as its own list of links if drupal_render() is called on it, but calling drupal_render() on the parent element will still produce a single list containing all the remaining links, regardless of what group they were in.

A typical example comes from node links, which are stored in a renderable array similar to this:

$build['links'] = array(
  '#theme' => 'links__node',
  '#pre_render' => array(
    'drupal_pre_render_links',
  ),
  'comment' => array(
    '#theme' => 'links__node__comment',
    '#links' => array(),
  ),
  'statistics' => array(
    '#theme' => 'links__node__statistics',
    '#links' => array(),
  ),
  'translation' => array(
    '#theme' => 'links__node__translation',
    '#links' => array(),
  ),
);

In this example, the links are grouped by functionality, which can be helpful to themers who want to display certain kinds of links independently. For example, adding this code to node.html.twig will result in the comment links being rendered as a single list:


{{ content.links.comment }}

(where a node's content has been transformed into $content before handing control to the node.html.twig template).

The pre_render function defined here allows the above flexibility, but also allows the following code to be used to render all remaining links into a single list, regardless of their group:


{{ content.links }}

In the above example, this will result in the statistics and translation links being rendered together in a single list (but not the comment links, which were rendered previously on their own).

Because of the way this function works, the individual properties of each group (for example, a group-specific #theme property such as 'links__node__comment' in the example above, or any other property such as #attributes or #pre_render that is attached to it) are only used when that group is rendered on its own. When the group is rendered together with other children, these child-specific properties are ignored, and only the overall properties of the parent are used.

3 string references to 'drupal_pre_render_links'
CommentLazyBuilders::renderLinks in core/modules/comment/src/CommentLazyBuilders.php
#lazy_builder callback; builds a comment's links.
FunctionsTest::testDrupalPreRenderLinks in core/modules/system/src/Tests/Theme/FunctionsTest.php
Test the use of drupal_pre_render_links() on a nested array of links.
NodeViewBuilder::renderLinks in core/modules/node/src/NodeViewBuilder.php
#lazy_builder callback; builds a node's links.

File

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

Code

function drupal_pre_render_links($element) {
  $element += array(
    '#links' => array(),
    '#attached' => array(),
  );
  foreach (Element::children($element) as $key) {
    $child =& $element[$key];

    // If the child has links which have not been printed yet and the user has
    // access to it, merge its links in to the parent.
    if (isset($child['#links']) && empty($child['#printed']) && Element::isVisibleElement($child)) {
      $element['#links'] += $child['#links'];

      // Mark the child as having been printed already (so that its links
      // cannot be mistakenly rendered twice).
      $child['#printed'] = TRUE;
    }

    // Merge attachments.
    if (isset($child['#attached'])) {
      $element['#attached'] = BubbleableMetadata::mergeAttachments($element['#attached'], $child['#attached']);
    }
  }
  return $element;
}