4

I have a loop populating multiple render arrays, and my output is not appearing as expected.

      $count = 0;
      foreach ($result as $row) {
      //do stuff

      if ($is_a_link_list) {
         //do more stuff

        $id = 'link_list_a' . $count;
        $content[$id] = array(
         //render array - link list
        );

      } else {

        $id = 'promo_list_a' . $count;
        $content[$id] = array(
            //render array - title
        );       
        $id = 'promo_list_b' . $count;
        $content[$id] = array(
            //render array - body
        );  

      }
      $count++;
    }

So in a given result set I'd expect:

---promo list title
   promo list body

---link list
   =item1
   =item2
   =item3

(more results)

What I'm getting:

---promo list title
   promo list body 

---link list
   =item1
   =item2
   =item3

   promo list body
---promo list title

---promo list title

---link list
   =item1
   =item2
   =item3

   promo list body

---link list
   =item1
   =item2
   =item3

So does the key of the render array matter? (Other than needing to be unique)

Looking at the markup output it's apparent that I need to render my render arrays as list items; I think this means a nested render array?

HTML source: Drupal 7 render array output

1
  • So I was able to fix my output issues, but my original question still stands. In case anybody has a similar issue; I fixed the output order by nesting the render array. I changed $content[$id] to $content[$count]['element_name'] I then used this answer to wrap each of my render array chunks in a container element; prefacing the if/else block with $content[$count] = array( '#type' => 'container', '#attributes' => array( 'class' => array('class-name'), ), );
    – Merrick
    Commented Mar 7, 2012 at 0:34

1 Answer 1

6

The order of the output for a render array is determined by the #weight attributes of it's contents. To reorder elements in a render array, set the #weight attribute of the target elements, using smaller values for elements that should appear earlier. Then set the #sorted attribute of the parent element to FALSE, this will make Drupal resort the elements of the render array before generating the output HTML. You can see an example of the technique in the Render Example module included in the Drupal Examples module. The relevant code is

$page['sidebar_first'] = array_reverse($page['sidebar_first']);
foreach (element_children($page['sidebar_first']) as $element) {
  // Reverse the weights if they exist.
  if (!empty($page['sidebar_first'][$element]['#weight'])) {
    $page['sidebar_first'][$element]['#weight'] *= -1;
  }
}
$page['sidebar_first']['#sorted'] = FALSE;

Now when Drupal goes to render the content, it will first be sorted according to #weight. Also note that elements which do not specify a #weight attribute are assigned a weight of 0 during sorting, so they will appear in the output in the order in which they are defined in the render array.

1
  • 1
    In case anyone is wondering where the sorting takes place, it's in element_children
    – Chaulky
    Commented Mar 7, 2012 at 4:47

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.