Problem/Motivation
Since #3443833: Provide a way for other modules to flag block plugin implementations as 'navigation safe' introduced a way to add additional types of blocks to be placed in Navigation via Layout Builder, it is now possible to add blocks that contain <form> tags when rendered. This means that after these blocks have been placed and saved, the layout cannot be saved again, because the layout form contains nested <form> tags. This identical problem affected default and override entity layouts in Layout Builder and was fixed in #3045171: Form blocks rendered inside layout builder break save. However, the fix was strictly limited to the entity view display form and the individual entity layout form.
Steps to reproduce
- Install Drupal with standard profile
- Install navigation module
- Create a block that has a form in it, such as a search block or views block with an exposed form
- Implement
hook_block_alter()in some module and set'allow_in_navigation'for the block's definition to TRUE. - Log in as administrator
- Go to /admin/config/user-interface/navigation-block
- Click on the +Add block link
- Click the link with the text matching the block's label
- Press the Add block button
- Press Save and confirm you see a successful "Saved navigation blocks" message
- (Optional) Go through similar steps to add any other block, but it's the same without doing it
- Press Save
- Observe that the warning message "You have unsaved changes." appears no matter how many times you press Save
Proposed resolution
The solution in [##3045171] use a form API #process callback added to the layout_builder element in DefaultsEntityForm and LayoutBuilderWidget, combined with a controller service decorator LayoutBuilderHtmlEntityFormController to move the layout builder element outside the form render array. This works because the layout builder element does not itself set values in form state, but instead interacts with the temp store to save layout data on form submit. However, the #process callback and controller apply only to the the entity form routes for the default entity display and entity layout. The navigation layout form is not a layout form, nor does Drupal\navigation\Form\LayoutForm add the #process callback to the layout builder element.
This is probably best solved by:
- Moving the
#processcallbacklayoutBuilderElementGetKeys()from the widget and the default display forms to the LayoutBuilder render element - Instead of decorating the entity form controller service, in the LayoutBuilder
#processcallback, add#pre_renderand#post_rendercallbacks to the containing form render array. In the #pre_render callback, render the layout builder element separate from the form, make sure to collect the cacheable metadata, and save the rendered markup as a non-renderable property. Then the in the #post_render callback, append the layout builder markup to the rendered from markup.
Remaining tasks
Postponed on reproducing a failing test in CI. Investigation: #3494332: Functional Javascript tests are silently skipped on Gitlab CI due to selenium standalone configuration
Test only build fails as expected now.
User interface changes
Introduced terminology
API changes
Data model changes
Release notes snippet
| Comment | File | Size | Author |
|---|---|---|---|
| #6 | 3493671-square.png | 123.67 KB | plopesc |
Issue fork drupal-3493671
Show commands
Start within a Git clone of the project using the version control instructions.
Or, if you do not have SSH keys set up on git.drupalcode.org:
- 3493671-placing-a-block
changes, plain diff MR !10539
- 3493671-test-only
changes, plain diff MR !10540
Comments
Comment #5
godotislatePut up MR 10539, which is ready for review. I'm not sure what's going on with the add tests, since the test-only job passes when it shouldn't. So I also pushed up a Test-only MR, which was failing in the wrong place. Meanwhile the test was consistently failing/passing as expected locally.
Comment #6
plopescThank you for noticing this and trying to help Navigation to be more stable. :)
Tested the MR code locally and fixes the issue with the form save process.
While testing it manually, noticed that a new blue rectangle appears on the Navigation Blocks page. See screenshot:

I think it could be easily removed using CSS, but wanted to flag it, just in case it could be an indicator of a possible issue.
Comment #7
godotislateOh, interesting. With the LB element moved outside the form, I assume it's picked up some sort of border CSS rule. Will investigate.
Comment #8
godotislateComment #9
godotislateAdded a class to the layout builder element and updated the CSS selector to hide the border.
Not sure what's going on with the test. I think there might be some difference between my local env and Gitlab CI for browser-based tests. I'll look into that later when I have to time to revisit.
Comment #12
godotislateCreated separate issue about strange behavior with the browser based tests not running as expected: #3494332: Functional Javascript tests are silently skipped on Gitlab CI due to selenium standalone configuration
Comment #13
godotislateRefactored so that an event subscriber isn't necessary. #pre_render and #post_render callbacks can handle it. Tests pass, but still not getting the test only build to fail as expected in CI, though.
Comment #14
plopescThank you for pushing this one!
Tested the feature branch manually after the refactor and it is working as expected, solving the reported bug for Navigation & Layout Builder integration. Also tested manually in an entity form and no regressions were noticed.
Added a minor comment in the MR.
Regarding the test only build, not sure if we could go ahead with this one, or some extra work might be needed.
Comment #15
godotislateThanks for the review, @plopesc. I made the suggested change as well as a similar one I forgot.
Not sure what's going on with the test. I created #3494332: Functional Javascript tests are silently skipped on Gitlab CI due to selenium standalone configuration, because I have observed some unexpected behavior going on with the browser-based tests at least, but I've made little headway in identifying the cause. Postponing this issue on the resolving the tests.
Comment #16
godotislateTried re-running the test-only job, and it failed as expected! https://git.drupalcode.org/issue/drupal-3493671/-/jobs/3825109.
I'm not sure what's different, but unpostponing and putting back to NR.
Comment #17
godotislateDid a bit of docblock clean up. Test only fails correctly still, so this is ready.
Comment #19
nicxvan commentedOk this was a doozy to test.
I pulled down 11.x and created a custom module with the block_alter and confirmed the issue occurs, checked this branch out and confirmed it is fixed.
Read through the code a few times, looks good once the two comments are addressed.
Comment #20
godotislateRebased and updated MR from review.
Test only job still failing as expected.
Comment #21
nicxvan commentedComments were addressed, looks great!
Comment #22
quietone commentedAfter reading the issue and MR, I didn't find any unanswered questions. I updated credit.
Comment #26
catchThis looks like a really nice clean-up, didn't expect a negative diffstat from the issue title.
Committed/pushed to 11.x, thanks!