Contextually modify a field input widget


This is an example from the rubric module of how you can contextually switch the input widget used when authoring content. In this example, a field_collection uses a formatter called field_collection_tabs_widget which allows for displaying and adding new field collections while working with a tab-like interface. This is great except when it comes to nested field_collections (which many projects have trouble handling). The 3rd party library it uses effectively makes it impossible to do nested tabs and so instead of fighting with it, I decided to switch the widget to the field_collection_fieldset render method when I know I'm going to run into UX problems.

Condition one looks and sees if we are on the node form and about to load tabs, we know not to do it (cause the node itself has a field collection tabs item. You'll notice this is the ENTITY_TYPE hook which means that this only fires when loading up a field collection. By doing this, we know that everything is already within a field_collection of some kind.

The second condition, looks for an even deeper field collection (it's 3 levels deep) by looking at arg(1) which will be a consistent field collection edit form. Then we match the type as tabs and look at the context of the field to see if it's the one that is nested inside other items.

Get raw version
  1. /**
  2.  * Implements hook_field_widget_properties_ENTITY_TYPE_alter().
  3.  *
  4.  * Divert widget styling methods for field collections based on how they
  5.  * are being accessed. tabs_widget doesn't work with nested field_collections
  6.  * so this is how we overcome that limitation by preventing it from rendering
  7.  * that way on the overall forms.
  8.  */
  9. function rubric_field_widget_properties_field_collection_item_alter(&$widget, $context) {
  10. // apply this on the node entry form, this way everything except the top
  11. // level tabs will be handled as collased fieldsets
  12. if (arg(0) == 'node' && $widget['type'] == 'field_collection_tabs') {
  13. $widget['type'] = 'field_collection_fieldset';
  14. $widget['module'] = 'field_collection_fieldset';
  15. $widget['settings'] = array(
  16. 'legend' => $widget['settings']['fctw_title_field'],
  17. 'collapsible' => TRUE,
  18. 'collapsed' => TRUE
  19. );
  20. }
  21. // don't apply to levels when categories are loaded
  22. if (arg(1) == 'field-rubric-categories' &&
  23. $widget['type'] == 'field_collection_tabs' &&
  24. $context['instance']['field_name'] == 'field_rubric_levels'
  25. ) {
  26. $widget['type'] = 'field_collection_fieldset';
  27. $widget['module'] = 'field_collection_fieldset';
  28. $widget['settings'] = array(
  29. 'legend' => $widget['settings']['fctw_title_field'],
  30. 'collapsible' => TRUE,
  31. 'collapsed' => TRUE
  32. );
  33. }
  34. }