Imaginons que nous ayons besoin d’ajouter une feuille de styles supplémentaire pour notre thème. C’est-à-dire un besoin hyper courant, que tout le monde a eu et aura encore. C’est d’ailleurs la première chose que l’on doit faire quand on crée un thème enfant !

Il y a plusieurs façons de charger le CSS et le JavaScript qui « marchent »: il y a la façon brutale, la façon WordPress presque correcte et la « vraie » façon WordPress.

La balise hardcodée

Une façon un peu brutale de charger vos ressources sur le devant du site est de hardcoder la balise <link> ou <script> dans le template header.php ou footer.php de votre thème.

Par exemple dans twentynineteen :

...
<!doctype html>
<html <?php language_attributes(); ?>>
<head>
    <meta charset="<?php bloginfo( 'charset' ); ?>" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <link rel="profile" href="https://gmpg.org/xfn/11" />
    <link rel="stylesheet" href="my-custom-styles.css">
    <?php wp_head(); ?>
</head>

<body <?php body_class(); ?>>
...

Boum. Ca va marcher, pas de souci. Mais quand vous allez avoir besoin d’un peu plus de contrôle, par exemple charger les styles de façon conditionnelle sur une page précise, cela va complexifier grandement votre fichier header.php, car vous aurez besoin d’ouvrir des balises PHP pour y insérer votre logique.

Et ne parlons pas de la mise à jour du thème si vous faites ça directement dans le parent. Certes, vous pouvez dupliquer entièrement le fichier header.php dans votre thème enfant, mais bon. C’est pas très propre tout ça.

L’intérêt d’un template, c’est de séparer la logique de l’affichage. Du coup, dans notre exemple précédent, on va à l’encontre de ce principe. Donc on va éviter de faire comme ça.

Hook sur wp_head

Dans la balise <head> du thème, on trouve la fonction wp_head(), qui a pour seul rôle d’exposer le hook du même nom.

Une autre façon de faire qui, elle, va nous permettre d’utiliser de la logique sans polluer le template, c’est de se greffer sur le hook wp_head.

On va supprimer notre balise hardcodée, et dans le fichier functions.php de notre thème, on va donc se hooker sur wp_head.

add_action( 'wp_head', 'example_head' );
/**
 * Adds <link> tag to <head> tag.
 */
function example_head(){
    if( is_page( 'sample-page' ) ){
        $stylesheet_url = get_theme_file_uri( 'assets/css/my-custom-styles.css' );
        printf( '<link rel="stylesheet" href="%s">', esc_url( $stylesheet_url ) );
    }
}

Dans cette fonction, on va simplement vérifier que l’on est sur une page spécifique ayant pour slug 'sample-page' grâce à la fonction is_page(), et si on est sur la bonne page, on va chercher l’url de notre feuille de style avec get_theme_file_uri() et on affiche la balise avec printf(). On prend juste le soin d’échapper l’url avec esc_url().

Si l’on navigue sur la page d’exemple de WordPress qui a pour slug sample-page en anglais, alors notre feuille de styles est chargée, et uniquement sur cette page.

Charger les ressources CSS et JS - CSS chargé
body { background-color: yellow; }. Joli, non ?

Cette méthode fonctionne et est un peu plus propre que la balise hardcodée, mais ce n’est pas encore parfait.

wp_enqueue_style() et wp_enqueue_script()

En réalité, voici la meilleure (la seule !) façon de charger des styles :

add_action( 'wp_enqueue_scripts', 'example_scripts' );
/**
 * Enqueues stylesheet and scripts.
 */
function example_scripts(){
    if( is_page( 'sample-page' ) ){
        $stylesheet_url = get_theme_file_uri( 'assets/css/my-custom-styles.css' );
        wp_enqueue_style( 'my-custom-styles', esc_url( $stylesheet_url ) );
    }
}

On se hooke sur wp_enqueue_scripts, pour utiliser ensuite la fonction wp_enqueue_style() pour charger nos styles.

wp_enqueue_scripts est le hook sur lequel WordPress s’attend à ce que les extensions et thèmes se greffent pour déclarer les styles et scripts à charger sur le devant du site, à l’aide des fonctions wp_enqueue_style() et wp_enqueue_script().

Pour être plus précis, les fonctions wp_enqueue_style() et wp_enqueue_script() ne chargent pas vraiment les ressources directement, mais les ajoutent à une file d’attente de ressources à charger, et WordPress va simplement écrire automatiquement les balises <link> ou <script> correspondantes sur wp_head ou wp_footer.

wp_enqueue_style()

La fonction prend 5 paramètres : wp_enqueue_style( string $handle, string $src = '', array $deps = array(), string|bool|null $ver = false, string $media = 'all' )

$handle est l’identifiant de la feuille de style et $src est l’url du fichier.

$deps est un tableau de dépendances. C’est-à-dire que vous pouvez passer un tableau d’identifiants de feuilles de styles (comme le $handle que vous venez de lui passer) et WordPress va faire en sorte que ces feuilles de styles soient chargées, et ce avant la votre. Magique, je vous dis.

On peut aussi passer un numéro de version $ver, qui sera ajoutée comme chaîne de requête à la fin de l’url de la ressource chargée. En général, j’évite de passer des numéros de version, car ce n’est pas très utile et cela peut révéler la version de l’extension ou du thème. Du coup, je passe souvent null pour ne rien ajouter à l’url. Sinon, lors du développement, vous pouvez passer time() pour éviter les soucis de cache. En effet, le numéro de version changeant à chaque rafraîchissement de page, vous aurez toujours une version fraîche de votre feuille de style.

$media permet de passer un type de média (screenprint, ou all) ou carrément une media query (max-width: 1280px) pour laquelle il faut charger la feuille de style. C’est surtout utile si vous avez une feuille de style spécifique pour le print. Pour le reste, en général les media queries sont dans votre feuille de styles.

Seuls les deux premiers paramètres sont obligatoires dans ce cas, mais souvent je vais jusqu’au 4e pour pouvoir explicitement dire à WordPress de ne pas ajouter de numéro de version, car par défaut, WordPress ajoute la version de WordPress comme numéro de version. C’est rarement une bonne idée de dévoiler la version de WordPress utilisée !

Du coup, on va ajuster notre morceau de code et ajouter les 3e et 4e paramètres :

add_action( 'wp_enqueue_scripts', 'example_scripts' );
/**
 * Enqueues stylesheet and scripts.
 */
function example_scripts(){
    if( is_page( 'sample-page' ) ){
        $stylesheet_url = get_theme_file_uri( 'assets/css/my-custom-styles.css' );
        wp_enqueue_style( 'my-custom-styles', esc_url( $stylesheet_url ), array(), null );
    }
}

Voilà qui est mieux.

wp_enqueue_script()

Pour charger vos fichiers JavaScript, on va utiliser la fonction wp_enqueue_script() qui va prendre presque les mêmes paramètres.

wp_enqueue_script( string $handle, string $src = '', array $deps = array(), string|bool|null $ver = false, bool $in_footer = false )

Comme wp_enqueue_style(), on doit lui passer un identifiant (slug) et une url vers le fichier à charger, et on peut lui passer un tableau de dépendances, ainsi qu’un numéro de version.

Par exemple, on peut lui passer array( 'jquery' ) si notre JS dépend de jQuery. La bibliothèque jQuery est incluse dans WordPress, et est utilisée partout dans l’administration. Elle est enregistrée comme script disponible et il suffit donc de passer son identifiant pour la charger correctement en tant que dépendance.

Notez qu’il vaut mieux utiliser la version du coeur de WordPress, même si elle est un peu vieillote. En effet, si vous chargez une version fraîche de jQuery dans votre thème et qu’une extension utilise aussi jQuery mais en chargeant celle de WordPress, vous risquez d’avoir les deux bibliothèques chargées, et des conflits peuvent apparaître. Elle est déjà dans le coeur, donc autant utiliser celle-ci.

Les différents scripts déjà enregistrés par WordPress et donc disponibles sont listés sur la page de documentation de la fonction : https://developer.wordpress.org/reference/functions/wp_enqueue_script/.

Le dernier paramètre $in_footer est très intéressant. Il permet de dire à WordPress si vous voulez que vos scripts soient chargés au plus tôt (dans la balise <head>) ou alors en bas de page (plus exactement sur wp_footer). Les ressources chargées dans la balise <head> vont bloquer le chargement et rendu du site, donc souvent, on recommande de charger les scripts non-essentiels en bas de page.

Pour l’exemple, on va créer un petit script alert.js dans notre dossier assets/js qui fait juste une petite alerte avec un message.

Pour charger ce script on va utiliser wp_enqueue_script(), mais on va charger le script dans la balise <head>.

add_action( 'wp_enqueue_scripts', 'example_scripts' );
/**
 * Enqueues stylesheet and scripts.
 */
function example_scripts(){
    if( is_page( 'sample-page' ) ){
        ...
    }
    wp_enqueue_script( 'alert', get_theme_file_uri( 'assets/js/alert.js' ) );
}
Charger les ressources CSS et JS - Script bloquant
Le script est bloquant

En se chargeant en haut de page et en s’exécutant de suite, le script bloque le reste de la page. Pour corriger cela, on va ajuster notre appel à la fonction :

wp_enqueue_script( 'alert', get_theme_file_uri( 'assets/js/alert.js' ), array(), null, true );
Charger les ressources CSS et JS - Script moins bloquant
Script moins bloquant, car en chargeant le script en bas de page, celle-ci s’affiche.

En passant simplement true comme valeur pour le paramètre $in_footer, notre page va s’afficher, mais s’il y a d’autres ressources chargées après la notre, celle-ci seront bloquées à cause du alert(), jusqu’à ce qu’on clique sur OK. Par exemple, malgré le fait que je suis connecté, la barre d’admin ne s’affiche pas.

wp_register_script() et wp_register_style()

Ces fonctions permettent de déclarer des styles et scripts mais ne les ajoutent pas à la file d’attente des ressources à charger. Elles ajoutent simplement les styles et scripts à la liste des ressources disponibles connues par WordPress. C’est tout.

Une fois déclarées, ces ressources peuvent être chargées très simplement avec wp_enqueue_style() ou wp_enqueue_script().

add_action( 'wp_enqueue_scripts', 'example_scripts' );
/**
 * Enqueues stylesheet and scripts.
 */
function example_scripts(){
    $stylesheet_url = get_theme_file_uri( 'assets/css/my-custom-styles.css' );
    wp_register_style( 'my-custom-styles', esc_url( $stylesheet_url ), array(), null );
    if( is_page( 'sample-page' ) ){
        wp_enqueue_style( 'my-custom-styles' );
    }

    wp_register_script( 'alert', get_theme_file_uri( 'assets/js/alert.js' ), array(), null, true );
    wp_enqueue_script( 'alert' );
}

Ici, on travaille en deux temps. On déclare d’abord nos styles et scripts avec wp_register_style() et wp_register_script(), puis on les charge quand on en a besoin avec wp_enqueue_style() et wp_enqueue_script()Vu que nos ressources sont déjà connues de WordPress, il suffit de passer leur identifiant pour les charger.

Dans notre exemple initial, on a uniquement utilisé wp_enqueue_style() et wp_enqueue_script() car elles permettent aussi de déclarer une ressource si elle n’existe pas déjà, puis de l’ajouter à la file d’attente. La fonction est un peu “deux en un”. Pratique.

Les fonctions wp_register_script() et wp_register_style() sont surtout utiles pour déclarer des scripts et styles utilisés comme dépendances, ou alors si vous voulez grouper toutes vos déclarations au même endroit mais que vous avez besoin de charger à des endroits différents.

Mais ce qu’il faut bien comprendre c’est qu’une ressource doit être déclarée et connue de WordPress pour pouvoir la charger correctement et au bon moment, et que wp_enqueue_style() et wp_enqueue_script() permettent à la fois de déclarer le cas échéant et de charger vos ressources.

wp_dequeue_style() et wp_dequeue_script()

Ces deux fonctions prennent simplement un identifiant $handle comme paramètre, et enlèvent les ressources correspondantes de la file d’attente des ressources à charger. Elles permettent simplement de ne pas charger une ressource.

Chargez vos ressources au bon moment

Charger les ressources sur le bon hook

Le moment attendu pour charger vos ressources sur le devant du site, c’est le hook wp_enqueue_scripts. Mais il existe d’autres hooks sur lesquels vous pouvez vous greffer dans d’autres situations.

Par exemple, vous pouvez vous greffer sur admin_enqueue_scripts pour charger des ressources uniquement disponibles dans l’administration, et sur login_enqueue_scripts pour la page de connexion.

add_action( 'admin_enqueue_scripts', 'example_admin_scripts', 10, 1 );
/**
 * Loads styles only on the general options page
 */
function example_admin_scripts( $hook_suffix ){
    if( 'options-general.php' === $hook_suffix ){
        wp_enqueue_style( 'admin-styles', get_theme_file_uri( 'assets/css/admin.css' ), array(), null );
    }
}

Le hook admin_enqueue_scripts fournit le slug de la page $hook_suffix qui permet de charger les ressources uniquement sur certaines pages. C’est très pratique.

Dans votre fonction de rappel, vous pouvez utiliser les fonctions de WordPress comme is_page(), is_home(), is_front_page(), ou vérifier le type de contenu affiché avec get_post_type() pour charger vos ressources sur le devant du site uniquement quand c’est nécessaire. Vous pouvez aussi lire la globale $pagenow dans l’administration.

Charger les ressources dans le modèle

Ces hooks couvrent les cas courants, mais il existe certains cas où il n’est pas possible de prévoir quand la ressource est requise.

Imaginez que, dans une extension, l’on ait besoin de créer un code court [wpcookbook_table] pour afficher un tableau. Mais ce tableau a besoin d’un peu de CSS et de JS personnalisé. Or, on ne sait pas sur quel page va se trouver le code court [wpcookbook_table], donc on ne peut pas utiliser la fonction is_page() ou autre !

Mais on sait que les fonctions wp_register_style() et wp_register_script()(tout comme wp_enqueue_style() et wp_enqueue_script()) ne font qu’enregistrer des ressources à charger plus tard.

Du coup, on peut directement utiliser ces fonctions dans la fonction de rappel de notre code court !

/**
 * Adds a simple shortcode displaying a table
 *
 * @param  string  $atts  shortcode attributes
 */
function example_table( $atts ){
    ob_start();
    printf( '<h2>%s</h2>', __( 'My custom table', 'example' ) );
    /** include table template here */
    $stylesheet_url = plugins_url( 'assets/css/custom-table.css', __FILE__ );    // Assuming this function is in bootstrap file
    wp_enqueue_style( 'custom-table-styles', esc_url( $stylesheet_url ), array(), null );
    wp_enqueue_script( 'custom-table-script', plugins_url( 'assets/js/custom-table.js', __FILE__ ), array(), null, true );
    return ob_get_clean();
}

Ici, on enregistre la feuille de styles et le script, qui vont se charger automatiquement quand WordPress tombera sur wp_footer, mais ces ressources seront chargées uniquement sur les pages contenant le code court [wpcookbook_table]. En observant le code source de la page, on voit que nos ressources sont chargées en bas de page avec tous les autres scripts.

Charger les ressources CSS et JS - Ressources chargées
Nos ressources sont bien chargées

Pourquoi ?

On a vu les fonctions et hooks à utiliser pour charger les ressources CSS et JS. Mais pourquoi faut-il absolument utiliser ces méthodes ?

Simplement parce qu’en faisant ainsi vous passez par l’API mise en place par WordPress, et de ce fait il a connaissance de vos ressources. Elles sont inscrites au registre, si vous voulez.

Du coup, WordPress peut manipuler vos ressources et elles sont aussi disponibles pour les autres extensions qui auraient besoin d’y accéder.

Par exemple, si vous voulez ne pas inclure les styles par défaut d’une certaine extension, vous pouvez. Si l’extension en question fait les choses proprement et utilise wp_enqueue_script() et wp_enqueue_style(), alors vous pouvez intervenir et utiliser wp_dequeue_style() et wp_dequeue_script() au bon moment pour éviter de charger ses ressources CSS et JS et utiliser les votre.

Quel est le bon moment ? Cherchez simplement quand l’extension charge ses scripts, et greffez-vous au même endroit ! Il y a de grandes chances que ce soit sur wp_enqueue_scripts. Vous aurez probablement à jouer un peu avec les priorités, mais ça, je vous laisse chercher 😉 !

J’espère que cet article vous a aidé à comprendre comment charger les ressources JavaScript et CSS correctement dans WordPress. Que ce soit dans un thème ou extension, le process est le même ! Et au final, ce n’est pas si compliqué !

Bon courage ! Enjoy !

PS: Si vous avez aimé, jetez un oeil à mon guide WPCookBook. On y voit plus en détails comment naviguer dans les fichiers de vos thèmes et extensions, créer des réglages pour l’outil de personnalisation du thème et bien d’autres recettes et astuces utiles et concrètes ! A bientôt !