In instances where you have created field group styles with the API, you may have cases where you want the parent container processed last with all its children processed first.

In my case, I have a new custom Accordion and Tab style (http://drupal.org/project/foundation_group). When the groups are built initially, it is just read straight out of the database. Initially, nothing seems wrong. But when you add new items to put under the parent container, they get processed last, which breaks pre_render hooks and theming later on. Ideally, the group data should be built for the functions in the order in which they are nested (with the parent last), or have a hook that allows the group data to be altered so their ordering can be corrected before any pre rendering occurs.

What happens for me is the following:

Create groups (Parent Container) and create child groups (Container Items) and nest them. Everything works great.

Create more Container items, and nest into the parent. They don't show up, because the parent is processed before the new children (group ordering) which breaks the rest of the calls. I need the parent processed last, because it's using its own #theme callback.

I did a little work and could not find any existing hook throughout Drupal or Field Group to intercept this early on. Then, I added this to field_group_attach_groups, before the pre_render is attached to the $element:

drupal_alter('field_group_attach_groups', $element, $element['#groups']);

Then, in my module:

function foundation_group_field_group_attach_groups_alter(&$groups) {
  $types = _foundation_group_get_types(); // assigns 'parent' container types
  $parents = array();

  foreach ($groups as $key => $group) {
    if (in_array($group->format_type, $types)) {
      unset($groups[$key]);
      $parents[$key] = $group;
    }
  }

  if (count($parents)) {
    $groups += $parents;
  }
}

This allowed me to correctly order the groups to remove parent groups, then reinsert them at the end of the groups array. Then, the rest of the processing happens normally, where children are processed first, then parents (if you have a #theme callback, this is critical).

I think a new hook is a good idea, but maybe also the groups should be ordered in field_group_unpack? I am not sure what the latter suggestion would cause, so the alter hook seems like the best route. I attached a patch.

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

kevinquillen’s picture

Oops, in the example above, it should be:

drupal_alter('field_group_attach_groups', $element['#groups']);

kevinquillen’s picture

Version: 7.x-1.1 » 7.x-1.x-dev
Category: bug » feature
alexweber’s picture

Status: Active » Needs review

+1, this patch works as advertised and is as elegant a solution as any to this problem.

a.ross’s picture

Status: Needs review » Closed (works as designed)

This is the wrong way to solve the problem. I've mentioned before that you shouldn't change the hierarchy of the field groups, rather you should implement a theme function to render the children. It's really very simple when you grasp the idea that Render API code is rendered bottom-up.

And again, the order of the groups in the database is completely irrelevant, as they are ordered using weight when they are rendered, which is done with element_children().

kevinquillen’s picture

the order of the groups in the database is completely irrelevant, as they are ordered using weight when they are rendered

Except they don't seem to be? Because parent groups were being rendered in whatever order they were created, same for the children.

I am using theme functions to render the children and the group parent - I did try the other way but it seemed nothing had effect on the order of the groups being rendered, which resulted in HTML built for the entire field group being out of order.

I will take a second look.

a.ross’s picture

I think mentioning the function you need to use 3 times should be enough. Refer to the documentation I linked to before.
Again, the order of elements in Render API code says nothing about the order in which the resulting HTML code will be. The #weight property is used for that. Check the handbook for more information.

Note that many of these [render API] properties are documented in the Form API Reference because the Form API has always used Render API properties, but they've traditionally not been documented as Render API properties, which they clearly are now in Drupal 7.

// Returns an element's children and sorts them based on weight.
$children = element_children($element, TRUE);
a.ross’s picture

Also note that for this purpose you should define a theme hook using the render element property, not variables. This means that your theme implementation is responsible for rendering an element's children, which is what you need to be able to do. Then you implement that theme hook with a function, not a template file. I already pointed you to a commit of the Fieldgroup Table module where I did exactly that to fix the exact same issue you're facing now.

alexweber’s picture

@a.ross, thanks dude! After reading through your comments a few times, looking at that commit and working through it I managed to get it fully working without requiring any patches. Phew! :)

a.ross’s picture

Good to hear! Nice job. :)