Problem/Motivation
#2171269: Handle block rendering's #attributes correctly (fixes in-place editing of custom blocks) introduced a change where if a block's content render array contained #attributes, then those attributes would be merged into the block wrapper's attributes. This is improper for certain use cases such as forms in blocks where the attributes belong on the content's <form> element, not the wrapper.
For example a if a block returns something like this:
array(
'#attributes' => array(
'class' => array(
'foo-bar'
),
'data-test' => 'This is just a test'
),
'#markup' => 'This is block content'
);
The rendered HTML will be:
<div id="block-foobartest" class="foo-bar" data-test="This is just a test">
This is block content.
</div>
instead of:
<div id="block-foobartest">
<div class="content foo-bar" data-test="This is just a test">
This is block content.
</div>
</div>
Steps to reproduce
From #10:
- Install the Standard profile.
- Add the Search Form block to a region on the page, somewhere it isn't likely to be given special theming. It's already in the Secondary Menu and while it does exhibit the bug there it's harder to tell due to alterations that are made.
- Visit the site front page.
- Inspect the block's HTML.
Expected result
The form contained in the block should have the attribute drupal-data-selector="search-block-form-###".
Actual result
The block wrapping the form has the expected attribute.
Proposed resolution
Update BlockViewBuilder so that it applies the #wrapper_attributes from a block's content render array to the outer block wrapper instead of the content's #attributes.
Remaining tasks
Subsystem maintainer approvalGiven in #17- Make certain this change doesn't break anything else.
- Review
User interface changes
It's possible that themes could rely on the attributes that are being merged into the wrapper. The change might break CSS or JS that are selecting based on an attribute.
Introduced terminology
API changes
Data model changes
Release notes snippet
| Comment | File | Size | Author |
|---|---|---|---|
| #48 | block_attributes_bug.png | 14.29 KB | dcam |
| #23 | add-wrapper-attributes-to-block-2486267-23.patch | 1.5 KB | martygraphie |
| #10 | 2486267.png | 49.58 KB | effulgentsia |
| #5 | attributes_of_a_block-2486267-5-boom.patch | 1.13 KB | joelpittet |
Issue fork drupal-2486267
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:
- 2486267-block-attributes
changes, plain diff MR !12168
- 11.x
compare
- 2486267-attributes-of-a
changes, plain diff MR !1402
Comments
Comment #1
Anonymous (not verified) commentedComment #2
joelpittetThis is by design. If you are using bartik theme's templates you can pass in
#content_attributeslike what D7 had. We decided to remove some divs.Comment #3
Anonymous (not verified) commentedI understand the simplifying of D8's markup. but that is not what I have issue with.
My issues is that a block is providing a piece of content, which is a "unit" of content on its own, and should be immutable in a way. But the render engine will break this unit into pieces(ie. the render array) and it will steal attributes out of it and pass it to the block itself rendering the original "unit" of content improperly.
Comment #4
joelpittetAh did a bit of research and see kinda what you are trying to explain. There is a specific comment to that effect.
core/modules/block/src/BlockViewBuilder.php:212I think you are write and we really should have been using #wrapper_attributes, to effect that outer element from our block plugin build() render arrary I think.
Am I following you @ivanjaros?
Comment #5
joelpittetHere's a quick patch to see how many test fail.
There is also a good chance this won't get into release considering it's next week. Don't want to get your hopes up @ivanjaros.
Comment #7
Anonymous (not verified) commentedYes, usage of #wrapper_attributes makes much more sense.
Comment #8
joelpittetLet's see if a framework manager can chime in here.
Comment #10
effulgentsia commentedI was curious how this affected SearchBlock, and found that most form attributes, such as
methodandactionare ok, because they're stored as#methodand#actionon the render array, rather than in#attributes. However, I did find that in HEAD,$form['#attributes']['data-drupal-selector']ends up getting moved from the<form>tag to the block's<div>wrapper, per the attached screenshot.The code in #4 was introduced in #2171269: Handle block rendering's #attributes correctly (fixes in-place editing of custom blocks), so adding it as a related issue, and I'll post a comment there asking for people who worked on that to comment here.
Prior to giving framework manager review on this, I'd like input from block.module maintainers, so tagging for that.
Comment #13
tisteegz commentedI am having this issue with trying to use theme item list. In my block class I have:
Instead of the class feeding through to the list it is being applied to the block. I am unsure on how to get around this to instead have the class applied to the list instead of the block. Will give the patch above in #5 a go however I am now up to Drupal 8.3 so I don't know if it is still going to apply.
Comment #14
Anonymous (not verified) commentedI think that you can wrap the array into an empty one and it should not bubble out but I'm not 100% sure.(return [[ ... ]]).
Comment #15
tisteegz commentedAh thanks! That worked perfectly.
Comment #17
tim.plunkettI agree this is a bug. And at first I wasn't sure how best to fix it without breaking BC.
Except that render arrays are exempted from the BC policy!
I think a switch to #wrapper_attributes would be good.
Comment #20
joumIs anyone comfortable enough to provide a workaround for this while a fix isn't available?
I'm trying to add attributes to a form but they keep getting bubbled up to the block's div.
Comment #22
martygraphie commentedHello,
I notice that the problem is still present, I have partially taken over the joelpittet patch. The latter solves the problem well
Comment #23
martygraphie commentedSorry the comment #22 doesn't have the right file, it's #23
Comment #24
martygraphie commentedComment #29
akram zairig commentedI've encountered the same issue on Drupal 9.0.14
Is there any working patch on Drupal 9 ?
Comment #34
johnjw59 commentedJust pushed a new commit that applies the same fix to blocks placed via layout builder.
Comment #36
smustgrave commentedthere doesn't appear to be anything to review the patch nor MR are passing tests.
And if this is a bug it will tests of it's own.
Comment #37
smustgrave commentedIs this a twig issue? Tried the MR and patch which both applied cleanly to 9.5.x but didn't do anything with the rendering.
Also is it really a bug ?
Current olivero block twig
To match change in description
Comment #38
taran2lThis is not a twig issue, and everyone agreed that this is an issue. Not sure what else is needed.
Comment #39
smustgrave commentedMaybe I don't fully understand the rendering but to get the output mentioned in the description don't you need to wrap in an additional div.
In an example block I'm using this is my build array
With or without the patch I'm seeing class, id, and data-test appear on the same div. So maybe this needs an issue summary update.
Comment #41
scottsawyerI am running into this problem with exposed forms in blocks, but it only surfaced when I updated to D 9.5. I was using views_block_filter_block because my views were block displays and I needed the exposed filters in separate blocks. It seems like the D9 update superseded views_block_filter_block, changing where the attributes were attached.
I patched with the MR, but it doesn't seem to be working, exposed form class attributes are still being moved to the containing block. If you have a custom block template for blocks containing views exposed forms that don't output all of the attributes, it breaks the ajax as well as the CSS in my case.
I worked around the issue by refactoring my template structure, I was fortunate to find a relatively simple solution, unfortunate that it cost me half a day to discover the problem and fix it.
Comment #45
dcam commentedBased on comment #10 I checked to see if this is still an issue in Drupal 11. It is. The same problem with the Search block form's
data-drupal-selectorattribute being applied to the block wrapper still exists.There was no need to make a new test for this. The test created for the related original issue, #2171269: Handle block rendering's #attributes correctly (fixes in-place editing of custom blocks), can be adapted to check the change.
MR 1402 was broken. I don't know why some of the additional changes in it were made because they aren't well documented. The change from
#atrributesto#wrapper_attributeswas lost. I think that's the reason for the confusion in the more recent comments. I'm sure that it stopped doing anything to fix the issue. Since it's difficult or impossible to rebase MRs for old Core versions anyway, I hid the branch and created a new one for D11 restarting from the #5 patch. We'll see if this causes other tests to fail.Comment #47
dcam commentedI didn't expect it to pass. I assumed that something else was probably relying on the attributes as they were. Oh well.
I made a change record: https://www.drupal.org/node/3525287.
Comment #48
dcam commentedI worked on this issue over the weekend not realizing that I'd experience it first-hand two days later. I've been adding inline styles to the
.views-exposed-formclass. Then I navigated to a different page where the exposed form is in a separate block. The class was bubbled up to the block wrapper, causing the block heading to be displayed in-line with the form as shown in the image below.Comment #49
smustgrave commentedThis seems like it could be an immediate breaking change if I had css written for before.
Comment #50
catchI ran into this logic recently on another issue and the current behaviour is very confusing as #48 demonstrates. We can't assume that everything rendered via block module is never rendered in any other context - especially with layout builder / experience builder and etc.
Comment #51
smustgrave commentedIf we aren’t concerned with #49 can add to my review list for tomorrow
Comment #52
dcam commentedI keep running into this error as I apply my new theme to more sites. But now I've had a WSoD crash because of it. I'm altering Views exposed forms to format them as USWDS Search components. It involves applying a few classes, changing the text input type to search, and setting
role="search"on the form. For some reason, that last one, setting the role attribute, really caused a problem when the exposed form is in a block and that block has its title display on.template_preprocess_block()(this site is still in D10) tries to set a unique ID for the block withHtml::getUniqueId(). When theroleattribute is bubbled up to the block due to this issue, suddenly the preprocess function starts passing the title render array togetUniqueId(). Then the error is thrown because the expected input is a string, not an array.I didn't bother trying to figure out what weird code path causes that to happen. I'm fortunate that I can simply turn the title display off in this one instance. I just want to point out that there are scenarios where this isn't harmless. I'm lucky that I knew about this issue so I could work out what was going on.
Comment #53
smustgrave commentedSorry to take so long, rebased the MR and it's got pipeline failures.
Feel free to ping me and I'll try and get to it sooner.
With regards to my concern if no one else has it I'll ignore it.
Comment #54
dcam commentedI've seen that random Unit test error twice before on another issue. It's unrelated.
Comment #55
dcam commentedI'm biased because it's been directly impacting me. Maybe we need to tag it for framework or even release manager review.
Comment #56
smustgrave commentedGoing to mark as this does fix the issue. Will tag but weird case I'm not sure needs framework manager sign off or not.
Comment #57
catchThis needs frontend framework manager review rather than framework manager review.
If it was possible we'd probably want a bc layer for this in stable9 so that themes depending on that get attributes in the same way as they do now, but not sure how we'd implement that.
Comment #59
needs-review-queue-bot commentedThe Needs Review Queue Bot tested this issue. It fails the Drupal core commit checks. Therefore, this issue status is now "Needs work".
This does not mean that the patch necessarily needs to be re-rolled or the MR rebased. Read the Issue Summary, the issue tags and the latest discussion here to determine what needs to be done.
Consult the Drupal Contributor Guide to find step-by-step guides for working with issues.
Comment #60
dcam commentedPost-bot-rebellion rebase
Comment #61
alexpott#57 needs addressing we've still not had a frontend framework manager review and a bc layer in stable9 would be good. I think we have to be concerned about breaking existing sites here.
Comment #62
dcam commentedI added backward compatibility to stable9. I even added a basic test for it.
Comment #63
needs-review-queue-bot commentedThe Needs Review Queue Bot tested this issue. It fails the Drupal core commit checks. Therefore, this issue status is now "Needs work".
This does not mean that the patch necessarily needs to be re-rolled or the MR rebased. Read the Issue Summary, the issue tags and the latest discussion here to determine what needs to be done.
Consult the Drupal Contributor Guide to find step-by-step guides for working with issues.
Comment #64
dcam commentedComment #65
nod_That works for me, CR is ok too.
Comment #66
catchOK this was a very tricky issue, the bc layer in stable9 and sign-off from @nod_ makes me a lot happier about committing it, thanks for sticking with it for 11 years everyone.
Committed/pushed to main and cherry-picked to 11.x, thanks!
Comment #71
quietone commentedReword the CR to put the change first and publish.