29

Using the Paragraphs module in Drupal 8, I am attempting to alter the behavior of the form fields contained within the paragraph field. This is so I can add behavior like AJAX callbacks, hide show other fields using states etc.

I can access the paragraph parent field using this function:

function hook_form_alter(&$form, \Drupal\Core\Form\FormStateInterface $form_state, $form_id) { 
}

But how do I access the fields inside the paragraph?

I have tried hook_field_widget_form_alter but to no avail.

How do I do this?

Note: I am still quite new to Drupal development.

1
  • Try this in your alter, kint($form); and kint($form_id); and that should give you the id for the hook id alter and then it should also give you the array paths for what you want to alter. Aug 8, 2016 at 14:34

9 Answers 9

31

Since paragraphs^1.3 you can use hook_field_widget_WIDGET_TYPE_form_alter() (I linked the 8.2 version because there is a good comment about using the hook).

You can see the following example in modules/contrib/paragraphs/tests/modules/paragraphs_test/paragraphs_test.module

/**  
 * Implements hook_field_widget_WIDGET_TYPE_form_alter().  
 */  
function paragraphs_test_field_widget_entity_reference_paragraphs_form_alter(&$element, &$form_state, $context) {
  if ($element['#paragraph_type'] == 'altered_paragraph') {
    $element['subform']['field_text']['widget'][0]['#title'] = 'Altered title';
  }
}
6
  • 21
    Note that if you are using the "Paragraphs EXPERIMENTAL" widget instead of "Paragraphs Classic", then the widget type is just paragraphs instead of entity_reference_paragraphs.
    – Dalin
    Dec 14, 2018 at 21:32
  • 2
    Some useful things (because it's impossible to debug these hooks): /* @var $paragraph \Drupal\paragraphs\Entity\Paragraph */ $paragraph = $form_state->get('paragraph'); $delta = $context['delta'];
    – Dalin
    Dec 14, 2018 at 22:12
  • 4
    I am not sure how to alter some paragraph fields when the edit mode of that paragraph is set to "closed" in the form display. Because in that case, the 'subform' does not return any of the inline fields. Apr 24, 2020 at 11:09
  • doesn't work for me but mymodule_field_widget_paragraphs_form_alter works, see below my answer if you are in the same case. Oct 9, 2020 at 9:15
  • 1
    FYI hook_field_widget_WIDGET_TYPE_form_alter is deprecated "in drupal:9.2.0 and is removed from drupal:10.0.0. Use hook_field_widget_single_element_WIDGET_TYPE_form_alter instead."
    – Jono
    Oct 13 at 11:34
13

If you are using Paragraphs Browser Field Widgets, then the WIDGET_TYPE ids for hook hook_field_widget_WIDGET_TYPE_form_alter() are different:

Field Widget Label Field Widget ID Provider
Paragraphs Classic entity_reference_paragraphs Paragraphs
Paragraphs EXPERIMENTAL paragraphs Paragraphs
Paragraphs Browser Classic entity_reference_paragraphs_browser Paragraphs Browser
Paragraphs Browser EXPERIMENTAL paragraphs_browser Paragraphs Browser
3

Solved! It works for me. hook_field_widget_WIDGET_TYPE_form_alter() Soution 1 is working for me.

Dependee Field: "field_align"

Dependent Field: "field_tab_sticky" & "field_tab_content"

/**
 * Implements hook_field_widget_WIDGET_TYPE_form_alter().
 */
function mymodule_field_widget_paragraphs_form_alter(&$element, &$form_state, $context) {
  if (!empty($element['subform']['field_dependee'])) {
    $parents_array = $element['subform']['#parents'];
    $parents = array_shift($parents_array) . '[' . implode('][', $parents_array) . ']';
    if (!empty($element['subform']['field_dependent'])) {
      $element['subform']['field_dependent']['#states'] = [
        'visible' => [
          ':input[name="' . $parents . '[field_dependee]"]' => [
            'value' => (string) 'some value',
          ],
        ],
      ];
    }
  }
}

enter image description here

Solution 1:

/**
 * Implements hook_field_widget_WIDGET_TYPE_form_alter().
 */
function HOOK_field_widget_paragraphs_form_alter(&$element, &$form_state, $context) {
  if (!empty($element['subform']['field_align'])) {
    $parents_array = $element['subform']['#parents'];
    $parents = array_shift($parents_array) . '[' . implode('][', $parents_array) . ']';
    if (!empty($element['subform']['field_tab_sticky'])) {
      $element['subform']['field_tab_sticky']['#states'] = [
        'visible' => [
          ':input[name="' . $parents . '[field_align]"]' => [
            'value' => (string) 'sticky',
          ],
        ],
      ];
    }
    if (!empty($element['subform']['field_tab_content'])) {
      $key = ':input[name="' . $parents . '[field_align]"]';
      $element['subform']['field_tab_content']['#states'] = [
        'visible' => [
          [$key => ['value' => (string) 'top']],
          'or',
          [$key => ['value' => (string) 'left']],
          'or',
          [$key => ['value' => (string) 'accordion']],
        ],
      ];
    }
  }
}

Solution 2: Refer

/**
 * Implements hook_field_widget_WIDGET_TYPE_form_alter().
 */
function HOOK_field_widget_paragraphs_form_alter(&$element, &$form_state, $context ) { 
  if($context['items']){

    $field_definition = $context['items']->getFieldDefinition();
    $paragraph_entity_reference_field_name = $field_definition->getName();

    if ($paragraph_entity_reference_field_name == 'field_content' && $element['#paragraph_type'] == 'tabs') { 

      $key = (isset($element['#type']) && $element['#type'] == 'container') ? $element['#field_parents'] : '';

      $widget_state = \Drupal\Core\Field\WidgetBase::getWidgetState($key, $paragraph_entity_reference_field_name, $form_state);

      $paragraph_instance = $widget_state['paragraphs'][$element['#delta']]['entity'];
      $paragraph_type = $paragraph_instance->bundle();

      if ($paragraph_type == 'tabs') {
        $dependee_field_name = 'field_align';
        $selector = sprintf('select[name="%s[%d][subform][%s]"]', $paragraph_entity_reference_field_name, $element['#delta'], $dependee_field_name);

        // Dependent fields.
        $element['subform']['field_tab_sticky']['#states'] = [
          'visible' => [
            $selector => ['value' => 'sticky'],
        ],
        ];

        // Dependent fields.
        $element['subform']['field_tab_content']['#states'] = [
          'visible' => [
            [$selector => ['value' => 'top']],
            'or',
            [$selector => ['value' => 'left']],
            'or',
            [$selector => ['value' => 'accordion']]
          ],
        ];
      }
    }
  }
}

Also, I agree with @baikho for hook references

1
1

Using hook_form_alter you could alter anything in the form, even stuff coming from widgets. It can easily get a bit messy and it tend to break easily when you mess around with widgets.

If you want to alter widgets what you can do it make your own widget. Widgets are plugins (PHP class) so you can make your own subclass the one you have and alter either by completely overwriting functions or by extending functions.

Widgets use annotation system, so you need to define name, id etc as comments above the class. Easiest way is simply to copy the original widget and alter give it a new name and id, rest should be like it needs to be.

Remember to clear cache to make Drupal find the new plugin.

1

If you are using Paragraphs Browser as field widget, things have one more twist for you. The hook that fits is named hook_field_widget_paragraphs_browser_form_alter() Took my quite some time to figure out...

1

In my case ( Drupal 8/9 - multi paragraphs entity reference field) hook mymodule_field_widget_entity_reference_paragraphs_form_alter doesn't work, I used mymodule_field_widget_paragraphs_form_alter like this :

<?php
/**
 * Implements hook_field_widget_WIDGET_TYPE_form_alter().
*/
function mymodule_field_widget_paragraphs_form_alter(&$element, &$form_state, $context) {
 if ( $element['#paragraph_type'] == 'content_selection') {
   //my specifid need 
   $element["subform"]["field_contents_related"]["widget"][0]["target_type"]["#options"]["taxonomy_term"] = t('Another text');
 }
}

Tips : to find quickly which field widget form alter is available in your form :

In core core/lib/Drupal/Core/Field/WidgetBase.php Just before :

\Drupal::moduleHandler()->alter(['field_widget_form', 'field_widget_' . $this->getPluginId() . '_form'], $element, $form_state, $context);

(in my case line 353 in protected function formSingleElement )

\Drupal::messenger()->addMessage('field_widget_' . $this->getPluginId() . '_form');

You will see all the form field widget alter in my case :

field_widget_datetime_timestamp_form field_widget_entity_browser_entity_reference_form field_widget_multiple_options_select_form field_widget_comment_default_form field_widget_dynamic_entity_reference_default_form field_widget_string_textfield_form field_widget_paragraphs_form field_widget_boolean_checkbox_form field_widget_options_buttons_form field_widget_text_textarea_form field_widget_metatag_firehose_form field_widget_entity_reference_autocomplete_form field_widget_language_select_form field_widget_path_form field_widget_datetime_timestamp_no_default_form field_widget_string_textarea_form

1
1

For Drupal 9.3 the hook_field_widget_WIDGET_TYPE_form_alter() is deprecated https://api.drupal.org/api/drupal/core%21modules%21field%21field.api.php/function/hook_field_widget_WIDGET_TYPE_form_alter/9.3.x

We should use hook_field_widget_single_element_WIDGET_TYPE_form_alter()

1

We shouldn't use hook_field_widget_WIDGET_TYPE_form_alter because this hook has been deprecated in drupal:9.2.0 and will be removed in 10.0.0.

Instead you should use hook_field_widget_single_element_WIDGET_TYPE_form_alter.

0

There's a patch for this in the Paragraphs issue queue.

It adds new hooks:

hook_form_paragraphs_subform_alter()
hook_form_paragraphs_subform_TYPE_alter()
hook_form_paragraphs_subform_WIDGET_alter()
hook_form_paragraphs_subform_WIDGET_TYPE_alter()
1
  • 9
    Per this comment, those hooks were not added in favor of core's hook_field_widget_WIDGET_TYPE_form_alter().
    – powpow12
    Feb 28, 2019 at 1:39

Your Answer

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

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