I have a custom content entity in which I have defined all the fields in the annotation (and it shouldn't need to be altered through the UI in any way that I can think of).
In the annotation I have the standard keys defined:
* entity_keys = {
* "id" = "MY_ID_FIELD",
* "label" = "MY_LABEL_FIELD",
* "uuid" = "uuid"
* },
MY_LABEL_FIELD is a field used for the "title" but I also need it presented in the content. In the entity class, I have it defined as I would need it displayed in the content:
->setDisplayOptions('view', array(
'label' => 'above',
'type' => 'string',
'weight' => 3,
))
Without any theme overrides, in the page content, MY_LABEL_FIELD renders as expected (and as defined in the annotation) with some basic field wrappers.
<div class="field ...">
<div class="field--label ..."> [the field's label...] </div>
<div class="field--item ..."> [the field's value...] </div>
</div>
But...
It renders the same way in the title block, with the field wrappers, in addition it is wrapped in <h1>
tags by page-title.html.twig
https://api.drupal.org/api/drupal/core%21modules%21system%21templates%21page-title.html.twig/8.2.x
And...
It renders as [the field's label...] [the field's value...]
inside the HTML <head><title>
tags.
https://api.drupal.org/api/drupal/core%21modules%21system%21templates%21html.html.twig/8.2.x
And...
I need to use the title value in my page template (page.html.twig). There is a title value available in $variables['page']['#title']
in
https://api.drupal.org/api/drupal/core%21includes%21theme.inc/function/template_preprocess_page/8.2.x but this title value is the same as HTML above, it is [the field's label...] [the field's value...]
In all 3 places, I simply want [the field's value...]
- without the label, without the wrappers. The only place I do want the label and wrappers is inside the content.
One solution is to implement a couple of HOOK_preprocess functions. Another is to implement a title callback.
This issue has been discussed here a number of times:
I tried implementing a title callback...
In my implementation of EntityRouteProviderInterface
$route = (new Route('/MY_PATH/{MY_ENTITY}'))
->addDefaults([
'_entity_view' => 'MY_ENTITY',
'_title_callback' => '\Drupal\MY_MODULE\Controller\MY_CONTROLLER::titleCallback',
])
->setRequirement('_entity_access', 'MY_ENTITY.view');
$route_collection->add('entity.MY_ENTITY.canonical', $route);
And in a controller
public function titleCallback() {
$entity = \Drupal::routeMatch()->getParameter('MY_ENTITY');
return $entity ? $entity->label() : 'SOME VALUE FOR FALSE';
}
And in my entity class, I implemented the label() method (override the parent class)
/**
* {@inheritdoc}
*/
public function label() {
return $this->get('MY_LABEL_FIELD')->value;
}
But I couldn't get this titleCallback() to ever get called. I started poking around a bit... I found that if I removed the "label" definition from the entity annotation, then the titleCallback() worked fine.
So this...
* entity_keys = {
* "id" = "MY_ID_FIELD",
* "label" = "MY_LABEL_FIELD",
* "uuid" = "uuid"
* },
became...
* entity_keys = {
* "id" = "MY_ID_FIELD",
* "uuid" = "uuid"
* },
Then everything seemed OK. MY_LABEL_FIELD was rendered with wrappers in the body and just the value was used in the page title block, the HLML <head><title>
and was a simple string available in $variables['page']['#title']
.
I moved on to other things.
I continued working on my module. This entity will hold nearly a million records and I started working on methods for loading all that data. After getting to a nice place with several hundred thousand records, I was doing some tests and getting some weird results, in particular entity reference autocomplete widgets pointing to this entity would just display a spinner (with only a few records it seemed fine). At first I thought it was a database issue with so many records, but eventually I discovered that if I put the "label" definition back into my annotation, all was fine again - except of course the title was being rendered with label and field wrappers.
I am guessing that the "label" definition is pretty important. I know it's not required, as my module would work without it. Also, a basic example https://www.drupal.org/docs/8/api/entity-api/create-a-custom-content-entity doesn't show it defined.
So I am not sure where to turn next:
I haven't actually discovered the code that gets the title value from an entity. Maybe someone could point me in that direction?
In HTMLRender class https://api.drupal.org/api/drupal/core%21lib%21Drupal%21Core%21Render%21MainContent%21HtmlRenderer.php/class/HtmlRenderer/8.2.x there is a call to a TitleResolverInterface https://api.drupal.org/api/drupal/core%21lib%21Drupal%21Core%21Controller%21TitleResolverInterface.php/interface/TitleResolverInterface/8.2.x that I should look into?
Maybe I should just handle it with theme overrides?
Or maybe in my entity class definition, I should define the field as I want it presented for titling purposes, and then deal with theming the field only for the content?
Thoughts?