Problem
This issue covers multiple problems relating to the function EntityViewController->buildTitle()
. This issue blocks #2353867: [META] Expose Title and other base fields in Manage Display and has adverse consequences in current vanilla core.
1 Malformed HTML output
In certain scenarios the page title region contains a div or h2 element inside h1, which is invalid markup.
Example scenario:
- Enable the media module.
- Create a media type and manage display to enable the name field
- Create a media entity, and view it at /media/1.
- Actual result: invalid markup div inside h1.
- Expected result: valid markup.
Cause is that buildTitle inserts the rendered output of a field into $page['#title']. In vanilla core:
- the field output comes from field.html.twig and contains a div
- the formatter may add further tags such as h2
- the page title output comes page-title.html.twig and wraps the title in h1
This bug does not affect user entity (no label) or node entity (specific workaround by means of field--node--title.html.twig - but that workaround causes problem 4).
2 Prevents manage display of label field
On the entity own page (such as /media/XX) the settings of manage display are ignored. The label field is missing from the main content, even if the title block is hidden.
This has been split off to a separate issue, #3043592: Allow entity to display label field as normal.
3 Inconsistent, only works selectively
The buildTitle function does not get called if the label field has been disabled by means of manage display. Hence the UX of the title block varies depending on a manage display setting (even though that setting potentially has no effect due to 2).
I analysed the tests that failed when removing buildTitle and discovered that we are relying on it for two unexpected things.
- HTML tags in page title: buildTitle escapes them, but template_preprocess_html strips them.
- Wrapper: for nodes field--node--title.html.twig is used and by default it wraps the page header title in a span
However both of these stop happening if the label field is disabled - inconsistency which is confusing and undesirable. For example it means that #2930788: Do not show name by default in media displays has surprising consequences.
4 Node titles missing label
If the site owner has hooked the node title to setDisplayConfigurable, then the title field display is incorrect, for example the label is missing.
Cause is the workaround code added for 1. The template field--node--title.html.twig overrides the normal field template with special case handling applicable if the display is not configurable. However the template gets used for configurable display too.
Overall effect
For any entity (such as core Media Entity) that allows manage display of the label, there is no safe option.
- If display is enabled, then get bad markup from 1).
- If display is disabled, then get potentially missing markup from 3).
There are contrib modules and core patches to extend manage display of label to more entities.
FYI Comment incorrect
The comment in buildTitle claims that the purpose is
allows attributes set on the field to propagate correctly (e.g. RDFa, in-place editing).
However RDFa works handles the title field in rdf_preprocess_node in a way that does not rely on buildTitle.
Proposed Solution
Enhance EntityViewController->buildTitle()
to switch between two alternatives.
1) "Legacy" = as existing code: set page title to the rendered title field formatter instead of the default plain text title. This is the default in Drupal 8, but is deprecated and will be removed before Drupal 9. This method has bugs if a module makes the field's display configurable via the field UI by means of of BaseFieldDefinition::setDisplayConfigurable().
2) "Template". Set page title to the output from the entity_page_title template; modules can use hook_preprocess_entity_page_title() to add attributes. Disable output of the label field in the main content. This will be the default in Drupal 9. It's not the default in Drupal 8, because it is not fully back-compatible with modules that rely on hook_preprocess_field() to set attributes on the page title.
Use the new "Template" if the label
- a module makes the field's display configurable via the field UI by means of BaseFieldDefinition::setDisplayConfigurable()
- AND the additional entity type property 'enable_page_title_template' has been set using hook_entity_type_build().
Rejected solution
Continue putting field into page title and fix all the bugs.
Downsides
- The code for putting field into page title is already somewhat complex and mysterious.
- We need to add more complex and mysterious code (see patch #26): pass a flag "is page title" into EntityViewController and EntityViewBuilder. That code doesn't really belong as those classes shouldn't care about page titles.
- We need to add more complex and mysterious code to make an inline field template (see patches in #2993647: Correctly determine when to display fields as inline). This likely forces all theme developers to alter their field template.
- Even after all this, there is a bug with quickedit. Patch #26 doesn't cover the case when the title is edited, and redrawn. To fix that we would need to make quickedit add an attribute to indicate a page title, and pass that information back on the AJAX request. So more complex and mysterious code.
The sole benefit of putting field into page title is to allow modules to write a preprocess function for all fields, and it 'magically' also works on the page title. However this is a dubious assumption - what works for a normal field isn't necessarily right for a page title - and has zero uses in core. (We will have to fix quickedit_preprocess_field
to handle the page title case specially anyway.)