Problem/motivation
Drupal 7 has most global site and page elements hardwired into templates, and gives no control to users to move them around. All the page elements (title, tabs, actions, breadcrumb, messages) are hardwired to core and contrib themes alike. We should stop special-casing these, so they can be moved around and selectively hidden or replaced as needed.
The page element "messages" needs special attention:
1) drupal_get_messages() returns messages only once
2) having block and page element at the same time is fragile
3) this block should use post-render callback to render messages later in page render
Proposed solution
- Introduce messages block that can be moved around.
- Remove special case item from themes.
- Introduce regions as needed to place these blocks.
- Introduce
MessagesBlockPluginInterface, which is implemented by the messages block. Just like we have MainContentBlockPluginInterface. Like the main content, messages are crucial — without messages, Drupal might look broken. By having an interface for the messages block (or alternative messages blocks), we can ensure that messages are present on the page: if the block isn't placed, we automatically provide a fallback.
Related issues
Split off from #507488: Convert page elements (local tasks, actions) into blocks
Beta phase evaluation
Reference: https://www.drupal.org/core/beta-changes
| Issue category |
Task because it's an improvement, not a fix. |
| Issue priority |
Major because this shouldn't hold up release, but is rather important for the Themer Experience (no more lots of special casing in the page template) and cacheability of Drupal 8. |
| Prioritized changes |
The main goal of this issue is performance + TX. |
| Disruption |
Only affects custom/contrib code that is using #theme => status_messages today, which will be a handful at most. They'll just have to replace #theme with #type, which is a trivial change (which could also be done by Drupal 8 Module Upgrader). |
Comments
Comment #1
rainbowarrayHere's the first version of this. Just splitting off messages from the rest of the patch now, with a couple minor tweaks. I'll take care of block__preprocess_page and the post render changes in the next version. The post render version stuff looks sort of complicated, but I'll try to work it out.
Comment #3
rainbowarrayComment #5
rainbowarrayTrying a different way to remove the page messages variable.
Comment #7
rainbowarrayI was unsetting the messages region rather than the messages variable.
Taking bets on if this fixes the fails or introduces a whole new slew of them.
Comment #9
rainbowarrayWell that's unfortunate.
Comment #10
rainbowarrayJust an experiment here. Checking what happens if I remove the block_preprocess_page function.
Comment #11
rainbowarrayFound a typo in Bartik's page template that was causing a problem. The interdiff is against patch 7, not patch 10. I don't think this will fix everything, but it might fix some of the fails.
Would be pretty neat if patch 7-11 was the winner. If so, I'm celebrating with a slushie.
Comment #14
rainbowarrayIf I had to bet as to what's going on here, it's this:
There are a lot of tests that add in the block module but still use the testing profile.
The minimal and standard profiles add a messages block to the messages region, but the testing profile does not, because the testing profile does not have blocks.
So if the block module is enabled, but there's no messages block installed with the testing profile, block_preprocess_page will still remove the messages variable from the template.
What would be good is if somehow block_preprocess_page could detect if there was at least one messages block placed in a region. If so, then remove the messages variable. That presumably would help things.
However it doesn't entirely explain all the failures because when block_preprocess_page was removed, there were still 811 fails and 4 exceptions. I'm not clear why.
Maybe I just screwed up the way that the messages post rendering is working.
Comment #15
rainbowarrayFound another dumb error I made. Ugh. Reworking the patching and testing it.
Comment #16
rainbowarrayI fixed a typo in the services definition (yay), but when I tested this, messages weren't showing up (boo).
There's a very good chance I'm doing this wrong. If anybody would like to take a look, I'd much appreciate it.
Comment #18
rainbowarraytimplunkett helped to rework the block_preprocess_page part. This now checks if a messages block is present before removing the messages variable. That should help.
Comment #20
rainbowarrayDown to 10 test failures. Much, much better.
All the tests that are failing are running on the standard profile, where the messages block is installed, and presumably the messages variable is removed from the page.
So since messages aren't actually showing up in the block, my guess is that the post render cache thing I set up is the problem here. We probably need Wim to figure out what's going wrong. But if you are not Wim, and you want to take a look at this, and you see something that looks off, that's cool too!
Comment #21
dawehnerJust a quick review ...
Can't you just skip this by using clear_queue=FALSE ?
Does it really make sense to introduce a new region and not reuse the content one?
Comment #22
wim leersWhile working on rerolling #1805054: Cache localized, access filtered, URL resolved, and rendered menu trees — which was green in the middle of June (#1805054-118: Cache localized, access filtered, URL resolved, and rendered menu trees) — I noticed something similar: my
#post_render_cachecallbacks in renderable arrays for blocks are never invoked! Please check if this is the case here as well; just put aprint 'YAY';exit;in the#post_render_cachecallback. If the page is rendered incompletely and you see "YAY", then my suspicion is wrong — and I hope I'm wrong.The reason:
There's an issue to fix this over at #2273277: Figure out a solution for the problematic interaction between the render system and the theme system when using #pre_render, and that also contains more info.
Important: this used to work just fine in mid June. So something may have changed block rendering-wise between June 16 and June 22 that causes this. But the overarching problem is #2273277, and that also just needs to be fixed.
Comment #23
rainbowarrayTime to revive this. Now that post render callbacks should be working correctly, we should be able to get this working.
Comment #24
wim leersIndeed, #2273277: Figure out a solution for the problematic interaction between the render system and the theme system when using #pre_render landed, which makes it possible to push this one forward again. I'll provide reviews!
Comment #25
manuel garcia commentedAttached a straight reroll of #18
Also, I wanted to mention some considerations now that we are moving twig files into classy in the Banana Phase 2:
New twig file:
Core twig files modified:
I put this here so that we can take a look down the road.
Comment #26
joelpittetThis @todo needs to be dealt with here. Any suggestions to make this work/go away?
Comment #28
wim leers#26: just remove it from
template_preprocess_page()andpage.html.twig?Comment #29
manuel garcia commentedOK, here is some work on this:
Fixed these two errors that were coming up on site installation:
And fixed also this one when you tried visiting the site:
I then tried to work on that @todo, but messages are not showing up apparently... could use some guidance!
Comment #31
wim leersI'm making the changes necessary to get messages to work again, to unblock you. Will post patch tomorrow morning CET.
Comment #32
wim leersFixed the patch, now messages show up, except that
show_messages(just grep for that and you'll about 1.5 dozen matches) is not yet taken into account, that's an important thing to fix still.That's patch 31.
But there's more :) This should either:
#post_render_cacheand keep\Drupal\system\Plugin\Block\SystemPageMessagesBlock::isCacheable()returningFALSE#post_render_cacheand make\Drupal\system\Plugin\Block\SystemPageMessagesBlock::isCacheable()returnTRUERight now, we're not caching it, and generating a render cache placeholder every request. That's pointless.
#post_render_cachealready ensures that something that is not cacheable becomes cacheable, by only storing a placeholder. Which makes the block perfectly cacheable.But…actually, only option 2 allows for the messages block being placed multiple times. So we should go with option 2.
And when doing that, we can also optimize things a bit more: instead of rendering the messages N times (for N messages blocks), having N
#post_render_cachecallbacks executed, and having to replace the placeholder in the HTML N times… we can reduce all those Ns to just 1. After all, each messages block must contain exactly the same messages. So by ensuring that we generate exactly the same placeholder, we can enforce that more optimal behavior :)Comment #35
wim leersNo actual changes in the number of test failures/exceptions, because those are not caused by messages not appearing, but by other things being broken :)
Comment #36
manuel garcia commentedLooking at the failing tests here... I see this warning all over the place on the failing tests:
mb_strtolower() expects parameter 1 to be string, object givenLine 299 on file
Unicode.phpfunctionDrupal\Component\Utility\Unicode::strtolower()Any clue what it is?
Comment #37
wim leersIt's receiving an object instead of a string. Just add a
to figure out which calling code is responsible.
Comment #38
lauriiiThis should fix some of the failing tests
Comment #40
joelpittetThanks for picking this up @Wim Leers and nice catch @lauriii.
Few little items when reviewing the code for this:
This is not necessary at all, won't change anything but not needed because it will just print nothing if empty. If you need to print messages just leave it in there, or move it if need be.
Same here.
This variable prep logic should be in preprocess and send the variable to the template.
Our indentation coding standards issues here. Each div should be nested in it's own line and we are indenting the after the if to be inline with twig coding standards.
Indent is weird here. One needs to go forward or back.
No need for the inline comment.
Those likely won't fix the problem but may help spot something that could inch it forward some more;)
Comment #41
lauriiiThis should fix some more tests.
Comment #43
lauriiiThanks @joelpittet for the review! I fixed points from #40.
Comment #44
lauriiiLets try this to fix most of the tests..
Comment #47
lauriiiHmm lets see now
Comment #48
joelpittetHoly cross post batman, that's twice crossposted with testbot and laurriii...
Thanks a bunch @lauriii for tracking down those bugs again and fixing the nitpicks, here's a couple more and a question on that preprocess/template.
Short array syntax.
Weird, I wonder why bartik only getting this? Shouldn't that be something core needs? And before, it was checking for the key messages is empty, could you do the equivalent in PHP?
One more of these unnecessary if statements.
Comment #50
lauriiiLets see if its going to right direction
I also removed messages variable from templates because the variable is not set anymore so I couldn't figure out why it should be still there
Comment #52
Scionar commentedComment #53
Scionar commentedAdded 'block' into modules array and system_page_messages_block added. Not enough time to do more. At Drupal-sprint FI.
Comment #54
Scionar commentedAdded interdiff.
Comment #55
manuel garcia commentedComment #57
wim leersIgnoring #53/#54 because it's several kilobytes less in patch size and the interdiff is suspiciously large.
Straight reroll of #50 (had to fix 2 conflicts), then pushing this forward a bit.
(No worries, Scionar, we've all been there. It takes a while to get that patch stuff going well :))
Comment #58
wim leersReview. Minor reroll attached, which fixes whitespace nits + point 3 below.
I'd like us to get rid of this, in favor of the approach in #507488-137: Convert page elements (local tasks, actions) into blocks, if possible. That'd be consistent with these other "essential page elements".
This doesn't actually work. E.g. for Bartik, this block is called
bartik_messages.It also seems unnecessary, because we don't do this for the main content block either.
This is never used, so we can significantly simplify
SystemPageMessagesBlock. Done.Don't we define logic like this in the Twig templates themselves nowadays?
I don't think the maintenance page (or install page) can ever use blocks. They have regions, yes, but not blocks.
So we'll need to make sure we fill the messages region with something even when the block module is disabled. Which is why I referred to that other issue earlier.
Comment #60
wim leersPageCacheTagsIntegrationTestComment #63
wim leersFixed a few tests.
Funny one:
BlockTestBase::setUp()was creating a messages block, but later during that function, all existing blocks are deleted… :) So it couldn't possibly work. This should help reduce the number of test failures by another bit.Fixing everything like this feels wrong though. See #58.1 & #58.5. Doing that now.]
EDIT: oops, debug additions while gearing up for that next step made it into this patch + interdiff. This will fail majestically.
Comment #65
wim leersReverted all changes in #63, except those in
BlockTest(Base). TheSimplePageVariant(used when block module is not active) now also renders messages. This is what is causing the majority of the test failures, and should thus help significantly in bringing this closer to zero test failures.Note that we want to remove the
drupalPlaceBlock()calls added in previous patches whenever we also had to enable theblockmodule.That leaves only one important matter to decide: when
blockmodule is enabled, do we require a messages block to be placed, or do we want to automatically provide a fallback? If we don't automatically provide a fallback (we currently don't, yet), then it's easy for a site builder to end up with a site that never shows messages (i.e. when the messages block is removed).Comment #67
wim leers593 fails. Much better.
Most of the remaining ones are probably for the case where block module is being used, but the messages block is not being placed yet.
Can't we make
WebTestBase::setUp()check which modules are being installed, and if the block module is also being installed, then place the messages block automatically?Comment #68
Jeff Burnz commentedJust thinking about that, won't we need a fallback to warn about placing a block? Could we possibly render messages via one of the core regions, like page.top if no block is placed, but provide a warning that the block should be placed?
Comment #69
fabianx commentedI think we should do it the same way as for MainContentInterface and PageTitleInterface have a PageMessagesInterface.
That is then:
a) Consistent with what we have elsewhere
b) Provides the fallback
c) Still makes it possible to configure the block
Comment #70
wim leersAgreed.
Done. This should be green or very close to green.
Next reroll: removing all those
drupalPlaceBlock()additions.Comment #71
wim leersNow we can make the patch significantly smaller.
I think the thousands of test failures above show we have sufficient test coverage.
Comment #72
wim leersWe will still have the failures caused by shortcut module'sshortcut_preprocess_page().LOL, no, that's in #507488: Convert page elements (local tasks, actions) into blocks. My bad.
Comment #75
wim leersUnfortunately still 30 fails (but that's >500 less than before), but fortunately #71 has exactly the same fails with a 28% smaller patch :) Hunting down those last 30.
Comment #76
fabianx commentedWe really really need to make this API easier to use. It is way too low-level.
Not the fault of this issue though.
Should use Cache::PERMANENT to make this explicit.
Except for the usage of hard-coded -1 and the failing tests this would be RTBC for me.
Comment #77
wim leers#76.1: indeed, out of scope here.
#76.2: fixed, great catch, I missed that :)
This reroll should fix the majority (if not all) of the remaining test failures. Summary of changes:
#theme => messages->#type => messages#post_render_cacheand hencedrupal_render_root()must be used. As should have been the case for all these AJAX command callbacks already anyway.Comment #79
wim leersInterdiff was right, patch was wrong. Rerolled.
Comment #80
fabianx commentedNeeds a change record OR change record updates for the #theme => #type change and integration.
Comment #81
wim leersDone: https://www.drupal.org/node/2446615
Comment #83
davidhernandezShouldn't there be a change record about the actual change here? Removing the availability of 'messages' for page templates and converting it into a block.
Comment #84
wim leers#83: good point, done: https://www.drupal.org/node/2446647 — mirrored after https://www.drupal.org/node/2410773
Comment #85
wim leersThis fixes the 3 failures in
BlockPageVariantTestand expands the test coverage.Comment #87
wim leersMost of the remaining failures were due to
#show_messageson theBareHtmlPageRenderer.But the failure in
SystemAuthorizeTestI spent hours debugging, thanks to this gem introduced in one of the patches above:… note how
page.contentis removed. ARGH!!!!!!This still won't be green, but will be very close.
Comment #89
wim leersA bunch of installer-related test failures appeared in #87 because the installer was now actually trying to show messages again, but doing so failed because the hash salt isn't set yet during the installation.
This will hopefully be green.
Comment #90
fabianx commentedUgh, that is unfortunate.
Not the fault of this patch, though.
Interdiff looks good! Lets see once we are green :).
Comment #91
fabianx commentedHas tests, has change record updates, the type messages here is fine and makes sense as you usually just place the block anyway.
Therefore:
RTBC! Great work!
Comment #92
wim leersAnd a bit of clean-up.
Most notable changes pointed out:
IMO the "page" part here should be omitted; this is just about "messages", period. There's nothing page-specific about them.
The only reason the "page" prefix is here, is because it used to be in the page template.
Why not just use
in Twig instead of creating this variable and then doing
?
A preprocess function is pointless here.
All this is copy/pasted directly from classy's template. So why not just inherit that? All Bartik wants is that wrapper.
Another reason: Classy's template has been improved since, and this template was not updated accordingly. By using inheritance, we prevent the need to keep them in sync manually.
Comment #93
wim leersAnd a tiny additional bit for
SimplePageVariant, to ensure messages are shown above.Comment #96
wim leersComment #97
fabianx commentedI would love to RTBC this, but looking closer again and re-reviewing all code, there is two things:
a) 'display' needs to be brought back as parameter, else this is an API change of sorts. (can just put in context and pass through to #post_render_cache, so should be fine - ).
+ $plugin_id => $context,but this will need to change to a key thats dependent on what is displayed else there will be only one item in post_render_cache as far as I have understood post_render_cache. (Might be wrong, but I know I had trouble with that notion when working my RenderCachePlaceholder class).
b) Template changes should quickly be verified by Cottser and the bartik changes by emmamaria. While the markup keeps the same the location changes and I know themers might care about this.
c) It might be nice (though probably - maybe not - out of scope) to add a configurable parameter to the block to select 'Status', Errors, etc.
That would actually be pretty cool to be able to place multiple blocks for that in different regions and probably a reason why a) display existed in the first place in the API.
And might be a good test case for a).
Comment #98
wim leersa)
Great catch.
So it's about bringing this back. It's not used by anything in core, but removing it would be an API change.
Done!
b) Agreed. Markup is identical before & after, but still, we want this to be verified.
c) That's indeed out of scope. Also a bad idea UX-wise — that should be available only to developers & themers. If we give users that choice, it's too easy to end up with a site that is broken. AFAIK it was always intended for developers & themers only. That's why it's only in the API and nowhere to be seen in the UI (in D8 nor D7/6/5).
Comment #99
star-szrAs requested here is a general review of the Twig/template action. Only minor points.
These 'template' lines should (hopefully) no longer be needed :D https://www.drupal.org/node/2231673
General question: why extend Classy's status messages template when everything is being replaced?
Anything but the default template from a module should not have @ingroup themeable - https://www.drupal.org/node/1823416#docblock
Unfortunately I just found that all or nearly all Classy templates have this same issue :/
In Classy's page.html.twig the 'messages' variable documentation is removed but page.messages is not added to the regions documentation like in the other templates.
Edited to add better context and expand one of the code snippets.
Comment #100
wim leersWe used to have this…
… and now it lives here.
Comment #101
star-szr@Wim Leers - I totally missed the use of
parent()- nicely done! I would be so happy to see that actually being used in core, or at least a core theme :)Comment #102
wim leers#101: Glad you like it :)
core/themes/bartik/templates/block--search-form-block.html.twigalready uses it though, so this won't be the first :)Comment #103
kim.pepperDid a quick review, and found one small nitpick:
Can we please have an issue for this?
Comment #104
rainbowarraySo happy to see this so close to getting in. Big thanks to all who worked to make that happen!
Comment #105
wim leers#103: AFAIK we don't file issues for D9 @todos? At least we don't for @deprecated stuff, which implies an @todo also. It's just a note when revising this in the future; hopefully the entire "bare HTML page renderer" concept can go away in D9. Since it's an API we'd rather get rid of, it feels unnecessary to file an issue for it.
Comment #106
emma.mariaPatch does not apply due to this commit #2349559: [meta] Discuss the organization of subfolders in Classy
Comment #107
emma.mariaComment #108
emma.mariaRerolled, I will now take a look at Bartik with this patch.
Comment #110
fabianx commentedI think this line will be the culprit:
+{% extends "@classy/system/status-messages.html.twig" %}it should be:{% extends "status-messages.html.twig" %} per https://www.drupal.org/node/2381103
so that it automatically extends from bartik...But hmm, that is the same file, so won't work, so need to specify the right path where system-messages.html.twig now lives after classy move.
--
Do we need a:
+{% extends "base-theme:status-messages.html.twig" %}or such directive in a follow-up?
Comment #111
davidhernandezComment #112
davidhernandezThe folder moved because of the Classy reorganization. This template file is extending a template with the same name, so the namespace and path to file has to be declared explicitly.
Comment #113
emma.mariaFrom a visual review of the patch, I noticed the messages block are in quite different places to where they originally were.
Admin pages
Messages printing at bottom of admin pages - in Seven and Bartik - this is a bug.
Seven - before patch
Seven - after patch
Bartik - before patch
Bartik - after patch
Frontend
Messages have moved from being just above content to below the title - which looks really different in Bartik
Bartik - before patch
Bartik - after patch
Classy - before patch
Classy - after patch
Comment #114
star-szrRe #110 don't want to derail but #2387069: {% extends "foo.html.twig" %} in Twig templates does not respect theme inheritance would be a good place to potentially add that follow-up mentioned as a related issue ;)
Comment #115
Jeff Burnz commented#113 is that on a new install, they look like they're not in the right regions?
Comment #116
emma.maria@Jeff Burnz I thought it was a fresh install, on reflection after that review at midnight I may try again.
Comment #118
emma.mariaNo I was right about the admin messages! On a fresh install the messages still print underneath the admin section as per #113.

%nbsp;
I dropped the database, cleared files and reinstalled Drupal with the patch applied.
Frontend messages work correctly, apologies for reporting them.
Comment #119
wim leersAdmin pages:
UPDATE: emmamaria has now indicated there's indeed no problem on the frontend.
Frontend:
Again, the Bartik problem you showed must be due to something being changed in the block layout because that cannot be reproduced with a fresh install.Classy isn't installed by default so what you're seeing here is the fallback behavior. This is expected. By placing a "Messages" block, the messages would appear in the original location again. Note that once #507488: Convert page elements (local tasks, actions) into blocks is solved, the "before" would again become reality, but because the title and local tasks are currently hardcoded in the page template, there is no way to make the default behavior match the "before" picture right now. (Unless we makeSimplePageVariantandBlockPageVariantrender the fallback messages in themessagesregion, but that should be avoided, since not every theme will have amessagesregion; we only require acontentregion.Comment #121
wim leersThe interdiff for #119 was correct, the patch was flawed (some other file snuck in).
Comment #122
fabianx commented> Seven didn't have a "Messages" block yet, so it was using the fallback.
But shouldn't that fallback end up in page.messages as well and hence be at the right position?
Comment #123
wim leers#122: No, see the deleted last bullet in #119.
Comment #124
fabianx commentedThanks for the explanation! :)
Comment #125
emma.mariaThe patch is still not happy.
Tried applying and get this mid applying...
Comment #126
wim leers#2449069: Remove default block_plugin cache tags, because they're useless caused that conflict. Straight reroll.
Comment #127
jibranIssue summary is not up to date with current patch approach and we do need beta evaluation. We also need a change record for
#type => 'status_messages'I don't see any reason for adding this.
Oh ok I see it's used in BlockPageVariant now
$messages_block_displayed = TRUE;can we add docs related to that here some @see and explanation would be great.Can we add a @code block in the docs with some examples here?
Can we add a @todo here #2278383: Create an injectible service for drupal_set_message()?
Let's not use deprecated functions.
Comment #128
fabianx commentedhttps://www.drupal.org/node/2446615 is the CR, leaving the rest to Wim.
Comment #129
emma.mariaPatch applies cleanly.
Messages print in the same places as core right now with the patch applied - admin and frontend, which is great.
Review of the Bartik theme.
I have a few nitpicks
In theory it should be below the menus and above Featured top, this is where it prints on the frontend.
<div class="region region-messages"></div>This can cause visual problems for Bartik. For example if messages are put in the Featured Top region, the region has a background colour and padding. It will print those styles no matter if there are messages or not. As we are making messages a block and flexible in placement, we should make sure the block doesn't break anything visually. See below...
Can this be changed?
Comment #130
wim leers#127:
As FabianX said, the CR already existed.
ViewsFormBase, because injecting it there causes a huge chain of changes.)#129:
Comment #131
emma.mariaThanks @Wim Leers for explaining everything to me. I came across those things when testing and was not aware of all of the history and other issues.
I agree with the patch changes and comments in #130. Bartik is signed off for this issue.
Comment #132
fabianx commentedBack to RTBC - if tests pass.
Comment #133
jibranWoW @Wim Leers you are awesome. This is ready just need beta evaluation and a little explanation for core dev related to current approach.
I don't this but do we have to update some doc files in a follow up or some meta issue to update http://api.drupal.org/api/drupal/developer%21topics%21forms_api_referenc...?
Comment #134
wim leersBeta evaluation added.
RE: FAPI reference: this isn't FAPI :) It's a
@RenderElement, not a@FormElement.Comment #135
wim leersIS updated to explain the approach in the patch better.
Comment #136
star-szrLooks great, thanks all especially @Wim Leers for driving this home!
Comment #137
alexpottCommitted d89c1f7 and pushed to 8.0.x. Thanks!
Thanks for adding the beta evaluation to the issue summary.
Made a code comment a bit more explicit on commit.
Comment #140
wim leersTestbot was probably testing this patch again immediately after it got committed.
Now let's continue over at #507488: Convert page elements (local tasks, actions) into blocks, which is now unblocked!
Comment #141
Jeff Burnz commentedHooray! Thank-you so much Wim, and everyone else who worked hard on this issue, massively appreciated.
Comment #142
wim leersPublished https://www.drupal.org/node/2446615 and https://www.drupal.org/node/2446647 :)
Comment #143
star-szr8 days later but I created the issue for #99.3 :) #2452361: Remove "@ingroup themeable" from all Classy templates