Injecter une balise dans <head> avec Drupal 8

Je vous partage une portion de code dont j'ai eu besoin de me servir à plusieurs reprises pour injecter des Google Fonts. J'avais tendance à l'injecter comme un goret dans le fichier de template html.html.twig mais ma conscience a fini par me rattraper pour faire cela proprement. Dans l'exemple je cherche à injecter l'appel à une police d'écriture de Google mais il peut vous servir à injecter n'importe quoi d'autre.

Si vous regardez html.html.twig, vous voyez que le contenu injecté dans <head></head> est généré de la façon suivante :

<!DOCTYPE html>
<html{{ html_attributes }}>
  <head>
    <head-placeholder token="{{ placeholder_token|raw }}">
    <title>{{ head_title|safe_join(' | ') }}</title>
    <css-placeholder token="{{ placeholder_token|raw }}">
    <js-placeholder token="{{ placeholder_token|raw }}">
  </head>

// Reste de la page.

Reste donc à comprendre comment le contenu de <head-placeholder> est généré. Mon réflexe dans ces cas là consiste à chercher dans le code du coeur si une portion de code significative (dans le sens "qui n'apparaît pas trop souvent comme résultat de recherche) m'aide à trouver comment ce bloc est créé. Pour cet exemple, je tente une recherche avec le mot-clé head-placeholder. Manque de bol, rien de significatif ne ressort.
Dans ce cas là, je change de tactique, je regarde le HTML final généré et tente une nouvelle recherche avec un autre élément significatif. Je relance cette fois ma recherche avec le mot-clé MobileOptimized. Bingo, je tombe sur le code de system_page_attachments() qui injecte cette balise. Je comprends dès lors que c'est le hook_page_attachments() qui se charge de la génération en injectant la balise qui m'intéresse.

<?php
/**
 * Implements hook_page_attachments().
 */
function system_page_attachments(array &$page) {
  //...
  // Attach default meta tags.
  $meta_default = array(
    //...
    // Attach default mobile meta tags for responsive design.
    'MobileOptimized' => array(
      '#tag' => 'meta',
      '#attributes' => array(
        'name' => 'MobileOptimized',
        'content' => 'width',
      ),
    ),
    // ...
  );
  foreach ($meta_default as $key => $value) {
    $page['#attached']['html_head'][] = [$value, $key];
  }
  // ...
}

Il ne me reste alors plus qu'à adapter cela à mes besoins pour injecter une Google Font sur toutes mes pages. Cela donne le snippet suivant.

<?php

/**
 * Implements hook_page_attachments().
 */
function monmodule_page_attachments(array &$attachments) {
  $google_font = array(
    '#tag' => 'link',
    '#attributes' => array(
      'rel' => 'stylesheet',
      'href' => 'https://fonts.googleapis.com/css?family=ABeeZee|Lora:400,700',
    ),
  );
  $attachments['#attached']['html_head'][] = [$google_font, 'google'];
}

Si vous voulez aller plus loin pour améliorer les performances et éviter le tracking de Google il est recommandé de récupérer les polices en local. Vous vous épargnerez les appels à un domaine externe. Sur les bon conseils de Monsieur opidentica, jetez un œil à ce script pour récupérer les polices Google fonts en local.

Commentaires

Anonyme Vendredi 7 octobre 2016 - 12:15
Précision complémentaire : On ne peut implémenter de hook_page_attachments() que dans un module. Dans un thème il faudra préférer hook_page_attachments_alter() qui fonctionne à peu près de la même manière.
Matthieu Vendredi 7 octobre 2016 - 13:29
Pour importer une police de caractère externe, j'utilise la méthode du librairies.yml de mon thème, à savoir (par exemple) : fonts: css: theme: //maxcdn.bootstrapcdn.com/font-awesome/4.6.3/css/font-awesome.min.css: { type: external, minified: true } //fonts.googleapis.com/css?family=Lato: { type: external } Et dans le fichier de déclaration de mon thème montheme.info.yml (mon avoir la police de caractère sur toutes les pages) : libraries: - montheme/fonts J'ai bon quand même ? ;-)

Votre commentaire

Le contenu de ce champ sera maintenu privé et ne sera pas affiché publiquement.
Votre adresse servira à afficher un Gravatar et à vous notifier des réponses. Votre commentaire sera anonymisé si ce billet est dépublié pendant plus de 3 mois.
Pour lutter contre le spam notre système enregistre votre adresse IP et votre adresse e-mail si vous la partagez.
Nous vous invitons à consulter notre politique de confidentialité pour comprendre les traitements faits de ces données et comment les rectifier.

À propos de Julien

Co-fondateur - Scrum master & Expert technique

Utilisateur de Drupal depuis 2008, j’ai fait mes armes comme développeur chez Commerce Guys puis me suis mis à encadrer les nouveaux arrivants avant de donner des formations, participer aux avant ventes et accompagner les équipes au passage à Scrum.

Je suis impliqué dans la communauté française de Drupal depuis 2009, j’ai été tour à tour président puis vice-président de l’association Drupal France et francophonie entre 2011 et 2013.