diff --git a/paragraphs.api.php b/paragraphs.api.php index 78403df..ae1cc85 100644 --- a/paragraphs.api.php +++ b/paragraphs.api.php @@ -48,5 +48,116 @@ function hook_paragraphs_widget_actions_alter(array &$widget_actions, array &$co } /** + * Perform alterations on a paragraphs entity subform. + * + * Modules can implement hook_form_paragraphs_subform_alter() to change a + * paragraphs entity subform in the entity reference widgets. + * + * In addition to hook_form_paragraphs_subform_alter(), there are more specific + * form hooks available. This allows targeting of a specific widget type and/or + * paragraphs type form directly. Within each module, the alter hooks are + * called in the following order: + * - hook_form_paragraphs_subform_alter() + * - hook_form_paragraphs_subform_TYPE_alter() + * With TYPE being the paragraphs type of the paragraphs entity. + * - hook_form_paragraphs_subform_WIDGET_alter() + * With WIDGET being 'classic' or 'experimental'. + * - hook_form_paragraphs_subform_WIDGET_TYPE_alter() + * With WIDGET being 'classic' or 'experimental' and TYPE being the + * paragraphs type of the paragraphs entity. + * + * @param array $subform + * Nested array of form elements for the paragraphs entity subform in the + * widget. + * @param \Drupal\Core\Form\FormStateInterface $form_state + * The current state of the form. The arguments that + * \Drupal::formBuilder()->getForm() was originally called with are available + * in the array $form_state->getBuildInfo()['args']. + * @param int $delta + * The order of this item in the array of sub-elements (0, 1, 2, etc.). + * + * @see hook_form_paragraphs_subform_TYPE_alter() + * @see hook_form_paragraphs_subform_WIDGET_alter() + * @see hook_form_paragraphs_subform_WIDGET_TYPE_alter() + */ +function hook_form_paragraphs_subform_alter(array &$subform, \Drupal\Core\Form\FormStateInterface $form_state, $delta) { + $paragraph = $form_state->get('paragraph'); +} + +/** + * Perform alterations on a paragraphs entity subform. + * + * Modules can implement hook_form_paragraphs_subform_TYPE_alter() to change + * a paragraphs entity subform in the entity reference widgets for a specific + * paragraphs type. + * + * @param array $subform + * Nested array of form elements for the paragraphs entity subform in the + * widget. + * @param \Drupal\Core\Form\FormStateInterface $form_state + * The current state of the form. The arguments that + * \Drupal::formBuilder()->getForm() was originally called with are available + * in the array $form_state->getBuildInfo()['args']. + * @param int $delta + * The order of this item in the array of sub-elements (0, 1, 2, etc.). + * + * @see hook_form_paragraphs_subform_alter() + * @see hook_form_paragraphs_subform_WIDGET_alter() + * @see hook_form_paragraphs_subform_WIDGET_TYPE_alter() + */ +function hook_form_paragraphs_subform_TYPE_alter(array &$subform, \Drupal\Core\Form\FormStateInterface $form_state, $delta) { + $paragraph = $form_state->get('paragraph'); +} + +/** + * Perform alterations on a paragraphs entity subform. + * + * Modules can implement hook_form_paragraphs_subform_WIDGET_alter() to change + * a paragraphs entity subform in a specific entity reference widget. + * + * @param array $subform + * Nested array of form elements for the paragraphs entity subform in the + * widget. + * @param \Drupal\Core\Form\FormStateInterface $form_state + * The current state of the form. The arguments that + * \Drupal::formBuilder()->getForm() was originally called with are available + * in the array $form_state->getBuildInfo()['args']. + * @param int $delta + * The order of this item in the array of sub-elements (0, 1, 2, etc.). + * + * @see hook_form_paragraphs_subform_alter() + * @see hook_form_paragraphs_subform_TYPE_alter() + * @see hook_form_paragraphs_subform_WIDGET_TYPE_alter() + */ +function hook_form_paragraphs_subform_WIDGET_alter(array &$subform, \Drupal\Core\Form\FormStateInterface $form_state, $delta) { + $paragraph = $form_state->get('paragraph'); +} + +/** + * Perform alterations on a paragraphs entity subform. + * + * Modules can implement hook_form_paragraphs_subform_WIDGET_TYPE_alter() to + * change a paragraphs entity subform in a specific entity reference widget for + * and a specific paragraphs type. + * + * @param array $subform + * Nested array of form elements for the paragraphs entity subform in the + * widget. + * @param \Drupal\Core\Form\FormStateInterface $form_state + * The current state of the form. The arguments that + * \Drupal::formBuilder()->getForm() was originally called with are available + * in the array $form_state->getBuildInfo()['args']. + * @param int $delta + * The order of this item in the array of sub-elements (0, 1, 2, etc.). + * + * @see hook_form_paragraphs_subform_alter() + * @see hook_form_paragraphs_subform_TYPE_alter() + * @see hook_form_paragraphs_subform_WIDGET_alter() + */ +function hook_form_paragraphs_subform_WIDGET_TYPE_alter(array &$subform, \Drupal\Core\Form\FormStateInterface $form_state, $delta) { + $paragraph = $form_state->get('paragraph'); +} + +/** * @} End of "addtogroup hooks". */ diff --git a/src/Plugin/Field/FieldWidget/InlineParagraphsWidget.php b/src/Plugin/Field/FieldWidget/InlineParagraphsWidget.php index 66697ad..57fcb5b 100644 --- a/src/Plugin/Field/FieldWidget/InlineParagraphsWidget.php +++ b/src/Plugin/Field/FieldWidget/InlineParagraphsWidget.php @@ -665,6 +665,14 @@ class InlineParagraphsWidget extends WidgetBase { } } } + $form_state->set('paragraph', $paragraphs_entity); + $hooks = [ + 'form_paragraphs_subform', + 'form_paragraphs_subform_' . $paragraphs_entity->getParagraphType()->id(), + 'form_paragraphs_subform_classic', + 'form_paragraphs_subform_classic_' . $paragraphs_entity->getParagraphType()->id(), + ]; + \Drupal::ModuleHandler()->alter($hooks, $element['subform'], $form_state, $delta); } elseif ($item_mode == 'preview') { $element['subform'] = array(); diff --git a/src/Plugin/Field/FieldWidget/ParagraphsWidget.php b/src/Plugin/Field/FieldWidget/ParagraphsWidget.php index 4b37b24..24dbff7 100644 --- a/src/Plugin/Field/FieldWidget/ParagraphsWidget.php +++ b/src/Plugin/Field/FieldWidget/ParagraphsWidget.php @@ -709,6 +709,14 @@ class ParagraphsWidget extends WidgetBase { } } } + $form_state->set('paragraph', $paragraphs_entity); + $hooks = [ + 'form_paragraphs_subform', + 'form_paragraphs_subform_' . $paragraphs_entity->getParagraphType()->id(), + 'form_paragraphs_subform_experimental', + 'form_paragraphs_subform_experimental_' . $paragraphs_entity->getParagraphType()->id(), + ]; + \Drupal::ModuleHandler()->alter($hooks, $element['subform'], $form_state, $delta); } elseif ($item_mode == 'closed') { $element['subform'] = []; diff --git a/tests/modules/paragraphs_test/paragraphs_test.module b/tests/modules/paragraphs_test/paragraphs_test.module index acec74d..21545d8 100644 --- a/tests/modules/paragraphs_test/paragraphs_test.module +++ b/tests/modules/paragraphs_test/paragraphs_test.module @@ -6,6 +6,7 @@ */ use Drupal\Core\Entity\Display\EntityViewDisplayInterface; +use Drupal\Core\Render\Element; use Drupal\paragraphs\ParagraphInterface; use Drupal\paragraphs\Plugin\Field\FieldWidget\ParagraphsWidget; @@ -41,3 +42,55 @@ function paragraphs_test_paragraph_view(array &$build, ParagraphInterface $entit $parent_field_name = $entity->get('parent_field_name')->value; drupal_set_message("Parent: $parent_type/$parent_id/$parent_field_name", 'status', TRUE); } + +/** + * Implements hook_form_paragraphs_subform_alter(). + */ +function paragraphs_test_form_paragraphs_subform_alter(array &$subform) { + foreach (Element::children($subform) as $key) { + // Check if container suffix empty. Needs to avoid join warning. + if (empty($subform[$key]['#suffix'])) { + $subform[$key]['#suffix'] = ''; + } + $subform[$key]['#suffix'] .= 'Here is element added by hook_form_paragraphs_subform_alter(). Key - ' . $key . '
'; + } +} + +/** + * Implements hook_form_paragraphs_subform_TYPE_alter(). + */ +function paragraphs_test_form_paragraphs_subform_text_paragraph_alter(array &$subform) { + foreach (Element::children($subform) as $key) { + // Check if container suffix empty. Needs to avoid join warning. + if (empty($subform[$key]['#suffix'])) { + $subform[$key]['#suffix'] = ''; + } + $subform[$key]['#suffix'] .= 'Here is subform for paragraph type `text_paragraph` added by hook_form_paragraphs_subform_TYPE_alter()
'; + } +} + +/** + * Implements hook_form_paragraphs_subform_WIDGET_alter(). + */ +function paragraphs_test_form_paragraphs_subform_experimental_alter(array &$subform) { + foreach (Element::children($subform) as $key) { + // Check if container suffix empty. Needs to avoid join warning. + if (empty($subform[$key]['#suffix'])) { + $subform[$key]['#suffix'] = ''; + } + $subform[$key]['#suffix'] .= 'Here is subform for experimental paragraph widget added by hook_form_paragraphs_subform_WIDGET_alter()
'; + } +} + +/** + * Implements hook_form_paragraphs_subform_WIDGET_TYPE_alter(). + */ +function paragraphs_test_form_paragraphs_subform_experimental_text_paragraph_alter(array &$subform) { + foreach (Element::children($subform) as $key) { + // Check if container suffix empty. Needs to avoid join warning. + if (empty($subform[$key]['#suffix'])) { + $subform[$key]['#suffix'] = ''; + } + $subform[$key]['#suffix'] .= 'Here is subform for experimental paragraph widget type `text_paragraph` added by hook_form_paragraphs_subform_WIDGET_TYPE_alter()
'; + } +} diff --git a/tests/src/Functional/ParagraphsExperimentalSubformTest.php b/tests/src/Functional/ParagraphsExperimentalSubformTest.php new file mode 100644 index 0000000..4e06a87 --- /dev/null +++ b/tests/src/Functional/ParagraphsExperimentalSubformTest.php @@ -0,0 +1,115 @@ +addParagraphedContentType('paragraphed_test'); + + $permissions = [ + 'administer content types', + 'administer node fields', + 'administer paragraphs types', + 'administer node form display', + 'administer paragraph fields', + 'administer paragraph form display', + 'create paragraphed_test content', + 'edit any paragraphed_test content', + ]; + $this->loginAsAdmin($permissions, TRUE); + + // Add new Paragraph types. + $this->addParagraphsType('text_paragraph'); + $this->addFieldtoParagraphType('text_paragraph', 'field_text', 'text_long'); + + $this->addParagraphsType('another_paragraph'); + $this->addFieldtoParagraphType('another_paragraph', 'field_title', 'string'); + + // Test for the node add form. + // New paragraphs. + $this->drupalGet('node/add/paragraphed_test'); + $this->getSession()->getPage()->findButton('field_paragraphs_text_paragraph_add_more')->press(); + $this->getSession()->getPage()->findButton('field_paragraphs_another_paragraph_add_more')->press(); + + // Checks that text added by hook_form_paragraphs_subform_alter() exists. + $this->assertSession()->pageTextContains('Here is element added by hook_form_paragraphs_subform_alter(). Key - field_text'); + $this->assertSession()->pageTextContains('Here is element added by hook_form_paragraphs_subform_alter(). Key - field_title'); + + // Checks text added by hook_form_paragraphs_subform_TYPE_alter() exists. + $this->assertSession()->pageTextContains('Here is subform for paragraph type `text_paragraph` added by hook_form_paragraphs_subform_TYPE_alter()'); + + // Checks text added by hook_form_paragraphs_subform_WIDGET_alter() exists. + $this->assertSession()->pageTextContains('Here is subform for experimental paragraph widget added by hook_form_paragraphs_subform_WIDGET_alter()'); + + // Checks text added by + // hook_form_paragraphs_subform_WIDGET_TYPE_alter() exists. + $this->assertSession()->pageTextContains('Here is subform for experimental paragraph widget type `text_paragraph` added by hook_form_paragraphs_subform_WIDGET_TYPE_alter()'); + + // Check for node editing with closed paragraphs. + $edit = [ + 'title[0][value]' => 'Paragraphs Subform test node', + 'field_paragraphs[0][subform][field_text][0][value]' => 'Text paragraph', + 'field_paragraphs[1][subform][field_title][0][value]' => 'Title paragraph', + ]; + $this->drupalPostForm(NULL, $edit, t('Save')); + $node = $this->drupalGetNodeByTitle('Paragraphs Subform test node'); + + // Set the settings to "Closed" to check that subforms are clean. + $settings = [ + 'edit_mode' => 'closed', + 'closed_mode' => 'summary', + 'autocollapse' => 'none', + ]; + $this->setParagraphsWidgetSettings('paragraphed_test', 'field_paragraphs', $settings); + + $this->drupalGet('node/' . $node->id() . '/edit'); + + // Check if all subforms are closed. + $this->assertSession()->pageTextNotContains('Here is element added by'); + $this->assertSession()->pageTextNotContains('Here is subform for experimental paragraph widget'); + + // Open first `text_paragraph`. + $this->getSession()->getPage()->findButton('field_paragraphs_0_edit')->press(); + + // It should contains all texts except 'Here is element added by + // hook_form_paragraphs_subform_alter(). Key - field_title'. + $this->assertSession()->pageTextContains('Here is element added by hook_form_paragraphs_subform_alter(). Key - field_text'); + $this->assertSession()->pageTextContains('Here is subform for paragraph type `text_paragraph` added by hook_form_paragraphs_subform_TYPE_alter()'); + $this->assertSession()->pageTextContains('Here is subform for experimental paragraph widget added by hook_form_paragraphs_subform_WIDGET_alter()'); + $this->assertSession()->pageTextContains('Here is subform for experimental paragraph widget type `text_paragraph` added by hook_form_paragraphs_subform_WIDGET_TYPE_alter()'); + $this->assertSession()->pageTextNotContains('Here is element added by hook_form_paragraphs_subform_alter(). Key - field_title'); + + } + +}