I have a Drupal link field configured to allow both internal and external links and have the title field enabled, but optional.

link field configuration

I want users to be able to reference internal entities without having to specify anything in separate title field, and have the Link field's title pulled from the entity label. However it appears that when the field's internal title value is left null, Drupal ends up using the field's uri value as the link title. This behavior seems odd to me.

My question is this: given an internal uri value that looks like: entity:node/3500 how can I preprocess or alter the functionality of the Link field to load in the entity's title/label as the title when it is left empty by the content editors.

I've searched for issues on drupal.org but didn't turn up much of anything useful. I found Get title from Route, which seems to recommend using the TitleResolver, but that depends on putting together a $request object, which seems extremely impractical.


  • 1
    Yes, the title resolver is impractical, also because it ignores caching. Load the node, translate it with getTranslationFromContext(), get the title and add the cache metadata of the node to the build array in preprocess. – 4k4 Nov 21 '18 at 8:03
  • @4k4 thanks. I've written a preprocess function to load the node based on routeParameters from the Url. Would appreciate your review, if you have a chance. See answer below. – JamesWilson Nov 21 '18 at 14:23

So, I've written a preprocess function to do this:

 * Prepares variables for link fields.
function mymoduleortheme_preprocess_field__link(&$variables) {

  // If the link is a reference to an internal entity and there was no
  // link title provided by the content editor, then use the entity
  // label as the link text.
  $i = 0;
  foreach ($variables['element']['#items'] as &$item) {
    if (empty($item->get('title')->getValue()) && $item->getUrl()->isRouted()) {
      $parameters = $item->getUrl()->getRouteParameters();
      if (!empty($parameters)) {
        foreach($parameters as $entity_type => $id) {
          if ($entity = \Drupal::entityTypeManager()->getStorage($entity_type)->load($id)) {
            $variables['items'][$i]['content']['#title'] = $entity->label();

This is working with both the standard Link field formatter as well as the "Separate link text and URL" formatter provided by Drupal 8 core.

Link field formatters

My only doubt here is that I'm not sure how safe it is to assume getRouteParameters() will always be keyed with an entity type name and a value of the entity id.

Would appreciate your help to review and vet this. Thanks!

  • 2
    I would check for the route name entity.[entity-type].canonical, then you can be sure there is a route parameter named [entity-type]. And add the cache metadata \Drupal::service('renderer')->addCacheableDependency($variables['items'][$i]['content'], $entity); – 4k4 Nov 21 '18 at 14:59
  • Gotcha. Wasn't sure about the cache thing. Thanks again. – JamesWilson Nov 22 '18 at 21:19

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.