diff --git a/src/Element/LayoutParagraphsBuilder.php b/src/Element/LayoutParagraphsBuilder.php index 7b8392cce1a7ab7e7b28dea31ef16342eb93828a..70f91bf54049831788540e2b3bab1c836c4250cb 100644 --- a/src/Element/LayoutParagraphsBuilder.php +++ b/src/Element/LayoutParagraphsBuilder.php @@ -399,25 +399,25 @@ class LayoutParagraphsBuilder extends RenderElement implements ContainerFactoryP */ public function postRenderComponent($content, array $element) { if (strpos($content, '<form') !== FALSE) { - // Rendering forms within the paragraph preview will break the parent - // form, so we need to strip form tags, "required" attributes, - // "form_token", and "form_id" to prevent the previewed form from - // being processed. + // Because the Layout Paragraphs Builder is often rendered within a form, + // we need to strip out any form tags, "name" attributes, and "required" + // attributes to prevent Drupal from attempting to process the form when + // the parent entity is saved. + // @see https://www.drupal.org/project/layout_paragraphs/issues/3263715 + // First, replace form tags with divs. $search = [ '<form', '</form>', - 'required="required"', - 'name="form_token"', - 'name="form_id"', ]; $replace = [ '<div', '</div>', - '', - '', - '', ]; $content = str_replace($search, $replace, $content); + // Strip out "name" attributes. + $content = preg_replace('/(<[^>]+) name\s*=\s*".*?"/i', '$1', $content); + // Strip out "required" attributes. + $content = preg_replace('/(<[^>]+) required\s*=\s*".*?"/i', '$1', $content); } return $content; } diff --git a/tests/modules/layout_paragraphs_form_rendering_test/layout_paragraphs_form_rendering_test.info.yml b/tests/modules/layout_paragraphs_form_rendering_test/layout_paragraphs_form_rendering_test.info.yml new file mode 100644 index 0000000000000000000000000000000000000000..82225191acc9359b9736c76f3d89be6a5386c161 --- /dev/null +++ b/tests/modules/layout_paragraphs_form_rendering_test/layout_paragraphs_form_rendering_test.info.yml @@ -0,0 +1,7 @@ +name: Layout Paragraphs Form Rendering Permissions Test +description: Tests rendering forms in builder components +core_version_requirement: ^8 || ^9 +type: module +package: Layout Paragraphs +dependencies: + - layout_paragraphs diff --git a/tests/modules/layout_paragraphs_form_rendering_test/layout_paragraphs_form_rendering_test.module b/tests/modules/layout_paragraphs_form_rendering_test/layout_paragraphs_form_rendering_test.module new file mode 100644 index 0000000000000000000000000000000000000000..c7a5a57d88b44197b8a1c8e38acba801b960a0c5 --- /dev/null +++ b/tests/modules/layout_paragraphs_form_rendering_test/layout_paragraphs_form_rendering_test.module @@ -0,0 +1,19 @@ +<?php + +/** + * @file + * Contains functionality for testing forms in the LP Builder. + */ + +use Drupal\Core\Entity\Display\EntityViewDisplayInterface; +use Drupal\Core\Entity\EntityInterface; + +/** + * Implements hook_paragraph_view(). + */ +function layout_paragraphs_form_rendering_test_paragraph_view(array &$build, EntityInterface $entity, EntityViewDisplayInterface $display, $view_mode) { + $build['lp_test_form'] = [ + 'form' => $form = \Drupal::formBuilder()->getForm('Drupal\layout_paragraphs_form_rendering_test\Form\TestForm'), + '#weight' => -1000, + ]; +} diff --git a/tests/modules/layout_paragraphs_form_rendering_test/src/Form/TestForm.php b/tests/modules/layout_paragraphs_form_rendering_test/src/Form/TestForm.php new file mode 100644 index 0000000000000000000000000000000000000000..59194a8a230f87f66b44ff67618cec7895dbaaa7 --- /dev/null +++ b/tests/modules/layout_paragraphs_form_rendering_test/src/Form/TestForm.php @@ -0,0 +1,47 @@ +<?php + +namespace Drupal\layout_paragraphs_form_rendering_test\Form; + +use Drupal\Core\Form\FormBase; +use Drupal\Core\Form\FormStateInterface; + +/** + * Provides a form for testing form rendering within the LP Builder. + * + * @see https://www.drupal.org/project/layout_paragraphs/issues/3263715 + * @see https://www.drupal.org/project/layout_paragraphs/issues/3258879 + */ +class TestForm extends FormBase { + + /** + * {@inheritDoc} + */ + public function getFormId() { + return 'layout_paragraphs_test_form'; + } + + /** + * {@inheritDoc} + */ + public function buildForm(array $form, FormStateInterface $form_state) { + // Intentionally named "title" to test for conflict with node title. + // @see https://www.drupal.org/project/layout_paragraphs/issues/3263715 + $form['title'] = [ + '#type' => 'textfield', + '#title' => $this->t('Test field'), + '#required' => TRUE, + ]; + $form['submit'] = [ + '#type' => 'submit', + '#value' => $this->t('Submit'), + ]; + return $form; + } + + /** + * {@inheritDoc} + */ + public function submitForm(array &$form, FormStateInterface $form_state) { + } + +} diff --git a/tests/src/FunctionalJavascript/FormRenderingTest.php b/tests/src/FunctionalJavascript/FormRenderingTest.php new file mode 100644 index 0000000000000000000000000000000000000000..645439913272416c22704ae225b58477a9b4ddc0 --- /dev/null +++ b/tests/src/FunctionalJavascript/FormRenderingTest.php @@ -0,0 +1,51 @@ +<?php + +namespace Drupal\Tests\layout_paragraphs\FunctionalJavascript; + +/** + * Tests forms rendered in paragraphs in the Layout Paragraphs Builder. + * + * @see https://www.drupal.org/project/layout_paragraphs/issues/3263715 + * @group layout_paragraphs + */ +class FormRenderingTest extends BuilderTestBase { + + /** + * {@inheritdoc} + */ + protected static $modules = [ + 'layout_paragraphs', + 'paragraphs', + 'node', + 'field', + 'field_ui', + 'block', + 'paragraphs_test', + 'layout_paragraphs_form_rendering_test', + ]; + + /** + * Tests rendering forms within a Layout Paragraphs Builder instance. + */ + public function testFormRendering() { + $this->loginWithPermissions([ + 'create page content', + 'edit own page content', + ]); + + $this->drupalGet('node/add/page'); + $page = $this->getSession()->getPage(); + + $this->addSectionComponent(0, '.lpb-btn--add'); + // Make sure the "Test field" form element appears. + $this->assertSession()->pageTextContains('Test field'); + // Save the node. + $this->submitForm([ + 'title[0][value]' => 'Node title', + ], 'Save'); + // Make sure the node appears correctly. + $this->assertSession()->pageTextContains('Node title'); + $this->assertSession()->pageTextContains('Test field'); + } + +}