Problem/Motivation
Drupal 7:
$title = drupal_get_title();
Drupal 8:
$request = \Drupal::request();
if ($route = $request->attributes->get(\Symfony\Cmf\Component\Routing\RouteObjectInterface::ROUTE_OBJECT)) {
$title = \Drupal::service('title_resolver')->getTitle($request, $route);
}
Do I need to tell more how is this wrong?
Proposed resolution
$title = Foo:bar()
Remaining tasks
Come up with a name, implement it.
User interface changes
API changes
| Comment | File | Size | Author |
|---|---|---|---|
| #29 | panels_page_variant_title-2264043-29.patch | 1.1 KB | mrinalini9 |
| #28 | 2264043-nr-bot.txt | 100 bytes | needs-review-queue-bot |
| #12 | panels_page_variant_title-2264043-12.patch | 1.11 KB | wim leers |
Comments
Comment #1
chx commentedComment #2
dawehnerUsing drupal_get_title() is not really a good approach in general, because it acts as it would get you the right one all the time.
The better way would be to use the page object once it does exists and get the title from there.
Comment #3
catch#2256669: [meta] Finalize module-facing API of getting the matched route name and a matched route argument for a request should improve getting the current route.
I don't think the second example in the issue summary actually works all the time, since we have the '#title' property used instead of calls to drupal_get_title() within page callbacks. Getting the title from the route is like manually invoking the title callback in 7.x - only covers half the possibilities. So the example code, while ugly, shouldn't be used anyway.
I think dawehner's right that the getter already exists: https://api.drupal.org/api/drupal/core%21lib%21Drupal%21Core%21Page%21Ht...
The question then becomes does everywhere have access to the HtmlPage object that might need it. This is 'needs more info' until that's documented.
#2218271: Theme preprocess functions have to futz with $page_object = $variables['page']['#page'] in weird ways is related since we're exposing the page object a bit too much there.
Comment #4
dawehnerIt basically comes down to the previous problem in D6/D7 that you might call drupal_get_title() to a point where some custom drupal_set_title() has not been called yet.
As far as I understand the problem most usecases actually deal with stuff on the page level, like some google analytics JS or really special theming. Panels could be another candidate for a usecase, but there you also work on the page level.
Comment #5
dawehnerThe time this object exists is during the kernel::view level. For example these events allow to pull the title to send it to some javascript.
what are other usecases?
Comment #6
benjy commentedIs there a new approach to this now HtmlPage and HtmlFragment are gone?
Comment #7
wim leersIndeed.
And that indeed was and is a problem.
Overall, the problem is that just using the usual title mechanism (routing system in D8, menu system in D7) only was able to account for static and "structured dynamic" titles. But we still have the need for "extremely dynamic" titles, and that's why in D7 and D8 alike, any code retrieving the page title (using
drupal_get_title()in D7) must run very, very late, or it will not return the correct result. Specifically, the main content callback must have already been called and have haddrupal_render()invoked.Good question. It's fundamentally still the same problem: any code wanting to get the page title must run extremely late.
Before we spend any more time on this, I think we should understand what the use cases are.
AFAIK the way D8 is designed, every route should have an associated title (let's call this "the routing title"). It is then possible for a
#titleproperty on the render array returned by the controller to override whatever the associated title would be (let's call this "the overriding title").This implies that e.g. for breadcrumbs it is expected that we use "the routing title" rather than "the overriding title", otherwise we'd have to execute the controller associated with each breadcrumb… which would be insane.
If I look at the
drupal_get_title()calls in D7 core, then I see 9 calls. Two are for test coverage. That leaves 7. One is for the page cache and is no longer needed. Leaves 6. One is for statistics.module, which is now done in JS, which makes more sense since it allows Drupal to serve from caches. Leaves 5. All remaining five occurrences are eitherhook_preprocess_page()implementations, where by design you can access the title, orhook_preprocess_html(), where the same applies.I would personally argue that those last five are the only sane use cases for getting "the final title", and in D8 you get them there without having to call a function with a "global static" to know which is the final title. And if people agree with that, then we can close this issue.
Unless somebody can think of a valid use case for something like
drupal_get_title(), keeping in mind that it is impossible to guarantee that you can call such a function at any time during the page generation time; we can only promise it works very, very late in the pipeline. The reason being that we want main content controllers be able to dynamically generate a title, and as a direct consequence, we can only get "the final title" very, very late. Especially Views needs this. If you want to work on removing that need, see #2359901: Discourage $main_content['#title'] in favor of route titles and title callbacks, where I attempted that, but got stuck.Comment #8
dawehnerWell there is a world outside of core, obviously.
Module would probably never use hook_preprocess_page to get the title, but isn't there a place where we have set the #title on the main content render array?
Currently there is no point in which
#titlepoints certainly to the proper title, but could we not provide a point to do that?Comment #9
wim leersOf course.
I don't see how, as long as we allow
$page['#title']. Drupal 8 aims to return as thin as possible render arrays (postponing as much work as possible to#pre_rendercallbacks, hence work we don't need to do on render cache hits). In many (most?) cases, the main content's#titlewill only be set by a#pre_rendercallback… which means the title will only be available after rendering the main content, which happens very, very late in the game: afterMainContentViewSubscribercallsHtmlRenderer. This happens before blocks are built. So we could make something likedrupal_get_title()(with a static variable in its implementation) work to get the current page's title for blocks. But it won't be available while rendering the main content.What's a good use case for using the current page's title in a block?
Comment #10
dawehnerOne really good usecase is the usecase of panels everywhere, which takes over the renderong of the full page.html.twig basically,
so you need to be able to get the title into that somehow.
One thing what panels did in d6/d7 was to be able to render things later, so render things after
all of the others ones was rendered. I think the corresponding functionality in D8 would be a #post_render callback
which fills in the title later. Do you think something like that on the level of the the page variant is a good idea?
Comment #11
catchUnless this is actually blocking panels everywhere, it looks like just an API addition to me and not critical. If someone can come up with a more common use case for getting the page title that's not met by the core API and is blocking contrib module/theme ports, we could reconsider.
Comment #12
wim leersYes! And this is actually almost completely supported by
HtmlRenderer+ page display variants already :)See
HtmlRenderer::prepare(). You'll see in there that we:$main_content$main_content['#title']as the title, if it is setbuild()method to generate$page$pageplus the title; we use$main_content['#title']if it's set, and otherwise we useTitleResolver(the returned title is used for<title>in the HTML<head>)This is theoretically enough already, because it means
PanelsPageVariantwould:$main_content['#title'], if the main content has a dynamic titlePanelsPageVariantcould callTitleResolveritself… but then in the second case,
HtmlRenderer::prepare()would retrieve the title again.So in order to resolve this, I think all that we want to do is change
to:
I.e. first try
$page(in case the page display variant callsTitleResolveror has its own logic to determine the title), then use the main content's title, if any, and finally, use theTitleResolveras the fallback.Thoughts? :)
Comment #17
dawehnerI'm wondering whether we could add a method to TitleResolver which is like:
getTitleForCurrentRequest(), it would at least get rid of most of the hassle?Comment #21
andypostComment #27
andypostThere's WIP patch
Comment #28
needs-review-queue-bot commentedThe Needs Review Queue Bot tested this issue. It no longer applies to Drupal core. Therefore, this issue status is now "Needs work".
Apart from a re-roll or rebase, this issue may need more work to address feedback in the issue or MR comments. To progress an issue, incorporate this feedback as part of the process of updating the issue. This helps other contributors to know what is outstanding.
Consult the Drupal Contributor Guide to find step-by-step guides for working with issues.
Comment #29
mrinalini9 commentedRerolled patch #12 for 10.1.x, please review it.
Thanks & Regards,
Mrinalini
Comment #30
smustgrave commentedThis issue is being reviewed by the kind folks in Slack, #needs-review-queue-initiative. We are working to keep the size of Needs Review queue [2700+ issues] to around 400 (1 month or less), following Review a patch or merge request as a guide.
This needs an issue summary update as the title and description talk about adding a getting method. But the patches are updating comments.