Need some help with your project? Contact me

Adding new HTML tags in the <head> in Drupal 8

In a previous article I've shown you how you can add new html elements to the <head> of your Drupal 7 site. Recently, however, I was working on a Drupal 8 project and encountered the need to do this in D8. And it took me a while to figure it out so I thought I'd share the process with you.

As you know, in Drupal 7 we use drupal_add_html_head() from anywhere in the code to add a rendered element into the <head>. This is done by passing a render array and most of the time you'll use the type #tag. In Drupal 8, however, we no longer have this procedural function so it can be a bit tricky to find out how this is done.

Although existing in Drupal 7 as well, the #attached key in render arrays really becomes important in D8. We can no longer add any scripts or stylesheets to any page without such proper attachment to render arrays. In my last article I've shown you how to add core scripts to pages in case they were missing (which can happen for anonymous users). In essence, it is all about libraries now that get attached to render arrays. So that is most of what you'll hear about.

But libraries are not the only thing you can attach to render arrays. You can also add elements to the head of the page in a similar way you'd attach libraries. So if we wanted to add a description meta tag to all of the pages on our site, we could implement hook_page_attachments() like so:

/**
 * Implements hook_page_attachments().
 */
function module_name_page_attachments(array &$page) {
  $description = [
    '#tag' => 'meta',
    '#attributes' => [
      'name' => 'description',
      'content' => 'This is my website.',
    ],
  ];
  $page['#attached']['html_head'][] = [$description, 'description'];
}

In the example above we are just adding a dummy description meta tag to all the pages. You probably won't want to apply that to all the pages though and rather have the content of the description tag read the title of the current node. In this case you can implement hook_entity_view() like so:

/**
 * Implements hook_entity_view().
 */
function demo_entity_view(array &$build, \Drupal\Core\Entity\EntityInterface $entity, \Drupal\Core\Entity\Display\EntityViewDisplayInterface $display, $view_mode, $langcode) {
  if ($entity->getEntityTypeId() !== 'node') {
    return;
  }

  $description = [
    '#tag' => 'meta',
    '#attributes' => [
      'name' => 'description',
      'content' => ['#plain_text' => $entity->title->value],
    ],
  ];
  $build['#attached']['html_head'][] = [$description, 'description'];
}

Now you targeting the node entities and using their titles as the content for the description meta tag. And that is pretty much it.

Hope this helps.

Comments

Thanks its works :)

Thanks for this.
For interest, SafeMarkup::checkPlain has been deprecated - https://www.drupal.org/node/2549395, and can be replaced with...

'content' =&gt; ['#plain_text' =&gt; $entity-&gt;title-&gt;value],

Also on a theme I'm working on, I'm not able to get hook_entity_view() to work. Is this a module-only hook? What would be the equivalent for a theme?

Hey, thanks for the update.

Indeed, that hook is a module hook. Chances are if you need that inside your theme, you are doing something wrong. Maybe you need a module to accompany your theme.

MODULNAME.libraries.yml file with this code is required:
~~~
dependencies:
- core/drupalSettings" required!
~~~'

Hi!!

Thanks for this great tutorial

I trying to migrate my module from D7 to D8 and i'll like to know if i can use #post_render in hook_entity_view since hook_page_alter has being removed?

is there any hook supporting #post_render callback in D8?

In the module approache, how would I add multiple attributes the most elegant way? Stried to expand the array, but only the last value was read. Do I have to repeat the " $page" function or is there a way to put them all in one array?

Add new comment

You must have Javascript enabled to use this form.