Adding Paragraph Behaviors Fieldset to Field Group tab

Created on 4 April 2024, 8 months ago
Updated 20 June 2024, 5 months ago

Problem/Motivation

I wanted a way to add the Behaviors fieldset to a "Styles" tab that I created using the Field Group module.

Resolution

I was able to get it to work by leveraging the MODULE_form_layout_paragraphs_component_form_alter hook and creating a submit callback. See code below. If there is a more elegant solution, please let me know.

/**
 * Alter the Layout Paragraph component form.
 *
 * Implements hook_form_FORM_ID_alter().
 *
 * @param array $form
 *   The Layout Paragraph component form.
 * @param \Drupal\Core\Form\FormStateInterface $form_state
 *   The Layout Paragraph Component Form State.
 *
 * @see layout_paragraphs_form_layout_paragraphs_component_form_alter()
 * */
function MODULE_form_layout_paragraphs_component_form_alter(array &$form, \Drupal\Core\Form\FormStateInterface &$form_state) {

  // Get the ID of the field group we want to add the behavior to
  $group_id = 'group_styles';

  // Cache the initial behavior fieldset render array
  $behavior_plugins = $form['behavior_plugins'];

  // Add behaviors to group mapping if not already set.
  if(!isset($form["#group_children"]['behavior_plugins'])) {
    $form["#group_children"]['behavior_plugins'] = $group_id;
  }

    // Add behaviors to group if not already added.
if(!empty($form["#fieldgroups"]) && !empty($form["#fieldgroups"][$group_id]) && !in_array('behavior_plugins', $form["#fieldgroups"][$group_id]->children)) {
    $form["#fieldgroups"][$group_id]->children[] = 'behavior_plugins';
  }

  // Open the details by default
  $behavior_plugins['#open'] = true;

  // Add fieldset to the group's render array
  $form[$group_id]['behavior_plugins'] = $behavior_plugins;

  // Visually hide the initial fieldset because we'll be updating the values based
  // on the cached version that we added to the field group above.
  $form['behavior_plugins']['#attributes']['class'][] = 'hidden';

  // Add submit callback
  array_unshift($form["#submit"], 'MODULE_layout_paragraphs_component_form_submit');
}

/**
 * Submit callback that updates the original fieldset with cached values.
 *
 * This function retrieves the cached values from the behavior fieldset and updates
 * the original fieldset accordingly after the form submission.
 *
 * @param array $form
 *   The form structure.
 * @param \Drupal\Core\Form\FormStateInterface $form_state
 *   The current state of the form.
 */
function MODULE_layout_paragraphs_component_form_submit(&$form, $form_state) {
  // ID of the field group
  $group_id = 'group_styles';

  // Get the new values from the cached version of the behavior fieldset 
  // and updated the original.
  $new_behavior_values = $form_state->getValue([$group_id, 'behavior_plugins']);
  if($new_behavior_values) {
    $form_state->setValue('behavior_plugins', $new_behavior_values);
  }
}

💬 Support request
Status

Active

Version

2.0

Component

Code

Created by

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Comments & Activities

  • Issue created by @jeremypeter
  • 🇨🇭Switzerland grumpy74 Geneva, CH 🇨🇭

    @jeremypeter, did you try to add your fields alterations using the form['#after_build'] callback instead ?

    In my case, I don't have an existing fieldgroup, otherwise I create 2 tabs (one for the fields of the paragraph and one for the behavior plugins) and the only way to make the alterations to work is using the after_build callback (as layout paragraph creates the behavior plugins on the #process callback, which is called after the form_alter hook).

    Using after_build will maybe spare you from managing a custom submit and a variables reassignment ?! I let you try in your fieldgroup context though.

    Here is my example if anyone wants to do so creating tabs dynamically :

    function yourmodulename_form_layout_paragraphs_component_form_alter(array &$form, FormStateInterface &$form_state) {
    
      // Create tabs for content fields and paragraph behavior for a better UI/UX.
      $form['tabs'] = array(
        '#type' => 'horizontal_tabs',
      );
    
      $form['tab_content'] = [
        '#type' => 'details',
        '#group' => 'tabs',
        '#title' => 'Content',
      ];
    
      $form['tab_behaviours'] = [
        '#type' => 'details',
        '#group' => 'tabs',
        '#title' => t('Settings'),
      ];
    
      // Content tab.
      // Add paragraphs fields in the content tab.
      $avoidedFieldsNames = ['behavior_plugins', 'actions', 'tabs', 'tab_content', 'tab_behaviours'];
      foreach (Element::children($form) as $field) {
        if(!in_array($field, $avoidedFieldsNames)) {
          $formField = $form[$field];
          $form['tab_content'][$field] = $formField;
          unset($form[$field]);
        }
      }
    
      // BEHAVIOUR TAB
      // Add after build custom method to set custom behaviour tab
      $form['behavior_plugins']['#type'] = 'container';
      $form['#after_build'][] = 'yourmodulename_behavior_plugins_form_after_build';
    }
    
    
    /**
     * Form after build.
     *
     * As the Behavior Plugins are created by Layout paragraphs using the "#process"
     * callback system, we need to operate our final alterations on the form on the
     * "#after_build" callback.
     *
     */
    function yourmodulename_behavior_plugins_form_after_build($form, &$form_state) {
    
      // Add custom behaviour tab with duplicate fields from original behavior plugins fields.
      $form['tab_behaviours']['behavior_plugins'] = $form['behavior_plugins'];
      $form['tab_behaviours']['behavior_plugins']['#group'] = 'tabs';
      $form['behavior_plugins']['#group'] = 'tabs';
    
      // hidde original behavior_plugins fields.
      $form['behavior_plugins']['#attributes']['class'][] = 'hidden';
    
      // horizontal tabs library.
      $form['#attached']['library'][] = 'field_group/formatter.horizontal_tabs';
    
      return $form;
    }
    
Production build 0.71.5 2024