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' => 'DrupalMY_MODULEControllerMY_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?