Override head title set by Metatag module in Drupal 8

Image by Pexels from Pixabay

Introduction

There are many ways to set or completely override page head title programmatically.
A most common approach is to use template_preprocess_html inside THEME_NAME.theme file.

However, this might not be suitable for modules which are supposed to control the page title without changing theme files.

The other approach is to put template_preprocess_html into a custom module or set title callback method inside module controller, but in this case, the title may get some extra additions from the Metatag module, for example, a [site:name] or so on.

Here we go to the solution of completely replacing the title set by Metatag module.

Solution

If we change module execution order by changing module weight and make our custom module work after the Metatag module applies its modifications, we should be able to see the updated title.

In Drupal 8, module weight is stored into ConfigFactory.

Get module weight:

$extension_config = \Drupal::configFactory()->getEditable('core.extension');
$module_weight = $extension_config->get("module.MODULE_NAME");

Set module weight:

module_set_weight('MODULE_NAME', 100);

However, there is a better method. Look into the metatag_preprocess_html function and see how the Metatag module overrides head_title variable with a value taken from the title attribute. We should find the way to change this attribute and make the Metatag module do all the rest of the work.

/**
 * Implements template_preprocess_html().
 */
function metatag_preprocess_html(&$variables) {
  if (!metatag_is_current_route_supported()) {
    return NULL;
  }
  $attachments = &drupal_static('metatag_attachments');
  if (is_null($attachments)) {
    $attachments = metatag_get_tags_from_route();
  }
  if (!$attachments) {
    return NULL;
  }
  // Load the page title.
  if (!empty($attachments['#attached']['html_head'])) {
    foreach ($attachments['#attached']['html_head'] as $key => $attachment) {
      if (!empty($attachment[1]) && $attachment[1] == 'title') {
        // Empty head_title to avoid the site name and slogan to be appended to
        // the meta title.
        $variables['head_title'] = [];
        $variables['head_title']['title'] = html_entity_decode($attachment[0]['#attributes']['content'], ENT_QUOTES);
        break;
      }
    }
  }
}

The next code example shows how to do it with a custom module hook or controller. This is almost the same code, but the key change is this the following: 

$attachments['#attached']['html_head'][$key][0]['#attributes']['content'] = $new_title;

You can use this snippet into module's hook or controller:

$attachments = &drupal_static('metatag_attachments');
if (is_null($attachments)) {
  $attachments = metatag_get_tags_from_route();
}
if (!$attachments) {
  return NULL;
}
if (!empty($attachments['#attached']['html_head'])) {
  foreach ($attachments['#attached']['html_head'] as $key => $attachment) {
    if (!empty($attachment[1]) && $attachment[1] == 'title') {
    // Here we set the new title value.
      $attachments['#attached']['html_head'][$key][0]['#attributes']['content'] = $new_title;
      break;
    }
  }
}  

This trick does the work and makes the Metatag module to override a title with our value.

Finally, see the full example of an overriding head title into module's template_preprocess_html

/**
 * Implements template_preprocess_html().
 */
function MODULENAME_preprocess_html(&$variables) {
  $moduleHandler = \Drupal::service('module_handler');
  if (!$moduleHandler->moduleExists('metatag')){  
    return NULL;
  }
  $attachments = &drupal_static('metatag_attachments');
  if (is_null($attachments)) {
    $attachments = metatag_get_tags_from_route();
  }
  if (!$attachments) {
    return NULL;
  }
  if (!empty($attachments['#attached']['html_head'])) {
    foreach ($attachments['#attached']['html_head'] as $key => $attachment) {
      if (!empty($attachment[1]) && $attachment[1] == 'title') {
        // Here we set our new head title.
        $attachments['#attached']['html_head'][$key][0]['#attributes']['content'] = 'New Head Title';
        break;
      }
    }
  }
}

Conclusion

The only condition of this solution to work is that it executes before metatag's template_preprocess_html

As mentioned earlier, the module's weight affects the execution order. Lower weights come earlier in the calling process. 
Also, the alphabetical order by module name is applied in case if the modules have the same weight.

The weight of the module can be changed with the hook_module_implements_alter or with Modules weight drupal project.

Add new comment

CAPTCHA
This question is for testing whether or not you are a human visitor and to prevent automated spam submissions.