We need to get page regions out of these hooks and only allow #attached.

Toolbar and a couple of other places still use it for other things. If they can be converted now we can convert them, but otherwise we'll need to add new code-only regions for the very top and bottom of the page (someone came up with page prepend and page append) for things like toolbar and devel query log to be put instead.

Comments

catch’s picture

dawehner’s picture

This certainly can first be started once we have moved the block rendering process out of hook_page_builder()

wim leers’s picture

Status: Active » Needs review
StatusFileSize
new23.8 KB
new1.36 KB

Having looked at this, we can only remove the block rendering process out of hook_page_build() in #2352155, see #2352155-4: Remove HtmlFragment/HtmlPage for related issues that explain why. In short: we've been working towards moving the block building into DefaultHtmlFragmentRenderer, and since that will go away, we also need to re-evaluate where block building should go in that context (block building is a specific page variant, so: "re-evaluate where instantiating a specific page variant should go" is the actual question).

But we already know we want to remove the concept of hook_page_build(), which allows any module to inject any random crap in any region, so we can already move forward with this, or at the very least begin the review process. This is the most contentious bit, and I've highlighted it in interdiff-contentious.txt.

Status: Needs review » Needs work

The last submitted patch, 3: hook_page_attachments-2350949-3.patch, failed testing.

wim leers’s picture

Status: Needs work » Needs review
StatusFileSize
new39.9 KB
new16.97 KB
wim leers’s picture

Noteworthy things that we must tackle in this issue/patch:

  1. We still had a block.install that altered block module's weight, specifically to allow other modules to alter its block in hook_page_alter()! Incredible, right?! I removed that.
  2. The bubbling of cache tags from the page_top and page_bottom "internal regions" is broken in HEAD, but is only exposed in this patch. This regression was also introduced by #2068471: Normalize Controller/View-listener behavior with a Page object.
  3. Fun fact: hook_page_alter() is used to wrap each region in the region "theme wrapper"!
  4. The documentation in theme.api.php has been updated to explain when themes should implement hook_page_attachments_alter().
  5. One test case in MainContentFallbackTest has become nonsensical/irrelevant: it used to test duplicating the main content to another region, but that is no longer allowed by hook_page_build(). So: removed that test case and documented the existing ones, we still have full test coverage.
catch’s picture

  1. +++ b/core/includes/common.inc
    @@ -2473,15 +2473,44 @@ function drupal_prepare_page($page) {
    +  $pseudo_page_for_attachments = [];
    

    Could we just call that $attachments? For implementors of this hook, it won't be a fake page any more, just an empty array and they're only adding elements to the top level.

  2. +++ b/core/includes/common.inc
    @@ -2473,15 +2473,44 @@ function drupal_prepare_page($page) {
    +    $function = $module . '_page_attachments';
    

    Can't use ModuleHandler::invokeAll()? If it's a merging issue could use a comment, but looks like artifact from original code.

General questions:

1. In Drupal 7 you had to add attachments to a region within the overall page array so $page['footer']['#attached'] - this is an unfixed bug in 7.x as far as I know, do we want to do do the empty array trick in system_page_attachments() then drupal_render_collect_attached() on the resulting array, or are we saying that all 8.x modules already add assets top level. Fine with either answer, it's simpler in the patch but it'd fail silently for an unported 7.x module.

2. The workaround for _block_page_build() I can probably live with to unblock other work, we could use a new critical to put that somewhere though. Looks to me like half of block_page_build() shouldn't be in there, and the other half is one or two lines.

wim leers’s picture

  1. Could we just call that $attachments? For implementors of this hook, it won't be a fake page any more, just an empty array and they're only adding elements to the top level.

    But the implementations of hook_page_attachments() operate by setting $page['#attached']['library'][] = 'mymodule/library'; — hence $attachments would be weird. Unless you're saying only the code <em>invoking</em> <code>hook_page_attachments() should use this $attachments variable name?

  2. Can't use ModuleHandler::invokeAll()? […] looks like an artifact […]

    I'd love that, but AFAICT that doesn't support passing arguments by reference, which this needs.

  3. RE: attachments in regions in D7: in Drupal 8, both work. No special cases.
  4. RE: _block_page_build(): I agree, that's why I have a @todo in there to fix it in #2352155: Remove HtmlFragment/HtmlPage. Isn't that sufficient?
catch’s picture

Unless you're saying only the code invoking hook_page_attachments() should use this $attachments variable name?

Yes just the code invoking.

E: attachments in regions in D7: in Drupal 8, both work. No special cases.

Does it still work after this patch though? We're only taking attachments out of $page['#attachments'], so if I add something to $page['foo']['#attachments'] I'd expect that to be ignored.

+++ b/core/includes/common.inc
@@ -2471,15 +2472,53 @@ function drupal_prepare_page($page) {
+    $page['#attached'] = $pseudo_page_for_attachments['#attached'];

Here we only get things out of the top level. That's fine for the invoker of hook_page_attachments(), but I'm not sure if system_page_build() should handle nested arrays.

If #2352155: Remove HtmlFragment/HtmlPage is the issue for _block_page_build() that's great.

wim leers’s picture

StatusFileSize
new47.9 KB
new10.5 KB

Yes just the code invoking.

Done.

Does it still work after this patch though? We're only taking attachments out of $page['#attachments'], so if I add something to $page['foo']['#attachments'] I'd expect that to be ignored.

Oh! I thought you were referring to $page['<region>']['#attached'] already being set, but you were referring to it being set in hook_page_build()! Hence you're right.
You said Fine with either answer, it's simpler in the patch but it'd fail silently for an unported 7.x module.. So you either want to see it be supported, or get an explicit failure. Makes sense.
I think explicit failure is better here, because it allows us to also explicitly fail if you're adding new render arrays in hook_page_build(), which we don't support anymore, and hence would also be silent failures (and developers will be wondering Why the hell is my content silently being discarded?! — not good!).
Done.

catch’s picture

Haven't done another line by line review yet but this looks good to me now.

moshe weitzman’s picture

Status: Needs review » Needs work

Code looks good to me. One significant bit of feedback and a couple nits:

  1. Why keep around hook_page_build() and hook_page_alter()? There should only be one way to do things. We are still in early beta. I think the minor inconvenience to module devs (a function rename) is less bad than having two ways to do things, for years. The BC implementation is ugly as well, jammed into system_page_attachments()
  2. throw new \LogicException('Only #attached and #post_render_cache may be set in hook_page_attachments_alter()');. Missing period.
  3. + // and, for backwards compatibility.missing the word: themes
catch’s picture

wim leers’s picture

Status: Needs work » Reviewed & tested by the community
Issue tags: +D8 cacheability, +sprint
StatusFileSize
new47.91 KB
new1.86 KB

RTBC per #11 and #12, since #12 only required nitpicks to be fixed.

Even if we decide to remove hook_page_build() and hook_page_alter(), that decision doesn't need to hold up this issue; that can be done in a non-critical follow-up. Moshe agreed with this.

Change record created.

Status: Reviewed & tested by the community » Needs work

The last submitted patch, 14: hook_page_attachments-2350949-14.patch, failed testing.

wim leers’s picture

Status: Needs work » Reviewed & tested by the community
StatusFileSize
new47.91 KB
new2.46 KB

I failed to update the exception messages everywhere to have trailing periods. Clearly, the test coverage works :)

catch’s picture

Only one actual change to make that I can do on commit, but just things that came up reading through:

  1. +++ b/core/modules/system/theme.api.php
    @@ -160,14 +160,24 @@
    + * We can distinguish between threetypes of assets:
    

    three types.

    Rest of the docs look good and clearly delineate what to use when.

  2. +++ b/core/modules/tour/tour.module
    @@ -63,9 +63,9 @@ function tour_toolbar() {
    +function tour_page_bottom(array &$page_bottom) {
    

    Long time no see, hook_footer() ;)

  3. +++ b/core/modules/update/update.module
    @@ -114,9 +114,9 @@ function update_help($route_name, RouteMatchInterface $route_match) {
    +function update_page_top() {
    

    Could use a follow-up to put this... somewhere else. Not sure where though. I'd almost leave it using the bc layer.

  4. +++ b/core/modules/user/user.module
    @@ -108,9 +108,9 @@ function user_theme() {
       $path = drupal_get_path('module', 'user');
    

    Not introduced here but should use __DIR__.

    The CSS here is only for the permissions and password element - we should probably add it conditionally in the permissions form and as #attached for that element. Again not here though.

catch’s picture

Title: Enforce that hook_page_build()/alter() can only be used for #attached » Add hook_page_attachments(_alter)() and deprecate hook_page_build/alter()
catch’s picture

Status: Reviewed & tested by the community » Fixed

Fixed #1 on commit.

Committed/pushed to 8.0.x, thanks!

  • catch committed 6cbb5d9 on
    Issue #2350949 by Wim Leers: Add hook_page_attachments(_alter)() and...
hass’s picture

How late is the attachment hook executed? It need to be the very very last...

berdir’s picture

@hass: No difference to before I think. Use hook_attachments_alter() if you want to be after most other attachment hook implementations. But at least devel also wants to be last, and it just dumps the page content, so you probably want it to win.

hass’s picture

It looks like hook_page_top and hook_page_bottom runs after hook_attachments_alter(). And blocks runs after hook_page_bottom(), too. That looks like the wrong order to me as I have no access to the final $page in hook_page_attachments_alter(). Just code wise...

And $page['#attached']['library'][] = 'google_analytics/google_analytics'; is also broken in hook_page_attachments() as it does not add the library to the page.

hass’s picture

Status: Fixed » Needs work
jhodgdon’s picture

As a note, if the docs need adjusting, all of these hooks have now been relocated to core/modules/system/theme.api.php instead of system.api.php where they were. See #2307859: Move theme/render hooks from system.api.php to theme.api.php

catch’s picture

Status: Needs work » Fixed

That looks like the wrong order to me as I have no access to the final $page in hook_page_attachments_alter()

That's by design and the entire point of adding this issue.

If there is a specific thing you're tryign to do, and you were previously unable to do it but now cannot, please open a new issue with clear steps to reproduce.

hass’s picture

$page['#attached']['library'][] = 'google_analytics/google_analytics'; is broken in hook_page_attachments() as it does not add the library to the page. This is a bug introduced by the patch here.

Please rollback the patch.

hass’s picture

#2365985: #attached library is broken in hook_page_attachments()/alter()

Please also explain me the design you are refering, too. The case summary does not explain anything and I have no idea why I cannot alter everything.

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.