Aller au contenu

Charger scripts et styles WordPress correctement

Chargez le JavaScript et le CSS de votre thème ou de votre extension avec wp_enqueue_script et wp_enqueue_style. Vous saurez choisir le bon hook, déclarer les dépendances, ajouter une version qui force le fureteur à récupérer le nouveau fichier, passer des données à un script et charger chaque fichier seulement là où il sert.

Vous avez un fichier JavaScript ou CSS à vous, dans un thème enfant ou une petite extension, et vous voulez que WordPress le charge sur les pages qui en ont besoin. Une balise <script> collée dans header.php fonctionne au début, jusqu’à ce qu’une extension charge la même bibliothèque deux fois, que le fureteur garde le fichier de la semaine dernière ou que la console signale une fonction non définie. La solution consiste à confier chaque fichier au système d’inclusion de WordPress, la file de scripts et de styles qu’il insère dans la page, à partir du hook qui correspond à l’écran visé. Chaque fichier reçoit un identifiant court et unique (le handle), la liste des identifiants dont il dépend et une version qui change chaque fois que le fichier change. Les étapes ci-dessous font passer un script et une feuille de style d’une balise codée en dur à une inclusion propre et conditionnelle.

Ce que vous allez accomplir

  • Enregistrer un script et une feuille de style avec un identifiant, des dépendances et une version tirée de la date de modification du fichier, pour que les fureteurs récupèrent le nouveau fichier dès le déploiement.
  • Les charger seulement sur les pages qui s’en servent, au lieu de toutes les requêtes.
  • Passer des réglages de PHP à votre script en JSON (le format de données que JavaScript lit directement), sans insérer de variables dans le gabarit avec echo.
  • Charger les fichiers d’administration sur votre propre écran de réglages et nulle part ailleurs dans wp-admin.
  • Prouver, en ligne de commande et dans le code source de la page, que chaque fichier se charge une seule fois, dans le bon ordre, avec la bonne version.

Prérequis

  • WordPress 6.3 ou plus récent. La forme tableau du cinquième argument de wp_enqueue_script(), avec in_footer et strategy, est arrivée dans la 6.3. Vérifiez avec wp core version : toute version à partir de 6.3 convient pour chaque étape.
  • PHP 8.1 ou plus récent. Rien dans le code n’exige une version plus récente.
  • Un endroit à vous pour le PHP : un thème enfant pour le code de présentation, ou une petite extension pour les fonctions qui doivent survivre à un changement de thème. Les exemples utilisent un dossier de thème enfant nommé sh-child, qui contient assets/js/slider.js et assets/css/slider.css.
  • La journalisation de débogage activée dans wp-config.php (WP_DEBUG et WP_DEBUG_LOG à true, WP_DEBUG_DISPLAY à false), pour que les avis aboutissent dans wp-content/debug.log plutôt qu’à l’écran.
  • WP-CLI, qui exécute les tâches d’administration de WordPress depuis un terminal, et curl pour les vérifications. Les deux sont facultatifs : l’affichage du code source dans le fureteur montre les mêmes balises.

Comment ça fonctionne

WordPress tient deux registres pour la requête en cours : un pour les scripts et un pour les styles. Enregistrer un fichier ajoute une entrée avec son identifiant, son URL, ses dépendances et sa version. Mettre un identifiant en file d’attente le marque pour l’affichage. Quand WordPress imprime la page, il parcourt la file, ajoute d’abord chaque dépendance, imprime chaque identifiant une seule fois et ajoute ?ver= suivi de votre version à l’URL. Une deuxième extension qui met en file le même identifiant n’obtient pas de deuxième copie, et c’est précisément la raison d’être du système.

Ces registres n’ont de sens qu’une fois que WordPress sait quel écran il construit. Voilà pourquoi on enregistre et on met en file à l’intérieur d’un hook d’action, et non en haut d’un fichier. Chaque type d’écran déclenche son propre hook, et celui que vous choisissez décide où vos fichiers apparaissent :

Six rangées associant chaque hook d'inclusion à un écran : wp_enqueue_scripts aux pages publiques, mis en évidence comme choix habituel; admin_enqueue_scripts aux écrans wp-admin; enqueue_block_editor_assets à l'interface de l'éditeur de blocs; enqueue_block_assets au contenu des blocs sur le site public et dans le canevas de l'éditeur; login_enqueue_scripts à l'écran de connexion; et le code placé en haut de functions.php, marqué trop tôt avec un avis _doing_it_wrong

Si les hooks sont nouveaux pour vous, le guide des actions et des filtres explique pourquoi une fonction attachée au mauvais moment ne fait rien. Pour l’inclusion, la règle est courte : utilisez wp_enqueue_scripts pour le site public, et choisissez un autre hook seulement quand le fichier appartient à un autre écran.

Étapes

  1. Retirez les balises codées en dur. Cherchez dans le thème enfant les balises qui pointent vers vos propres fichiers :
grep -rnE '<script[^>]+src=|<link[^>]+stylesheet' wp-content/themes/sh-child/ --include='*.php'

Exemple de sortie :

wp-content/themes/sh-child/header.php:14:<script src="/wp-content/themes/sh-child/assets/js/slider.js"></script>

Supprimez chaque ligne trouvée qui vise un fichier que vous allez inclure. Laissez wp_head() et wp_footer() en place. Ces deux appels sont l’endroit où WordPress imprime la file, et sans eux rien de ce que vous mettez en file n’apparaît. Si grep n’affiche rien, il n’y avait aucune balise codée en dur à retirer.

  1. Enregistrez les deux fichiers sur wp_enqueue_scripts. Ajoutez ceci au functions.php du thème enfant :
add_action( 'wp_enqueue_scripts', 'sh_register_slider_assets' );

function sh_register_slider_assets() {
    $css = 'assets/css/slider.css';
    $js  = 'assets/js/slider.js';

    wp_register_style(
        'sh-slider',
        get_theme_file_uri( $css ),
        array(),
        (string) filemtime( get_theme_file_path( $css ) )
    );

    wp_register_script(
        'sh-slider',
        get_theme_file_uri( $js ),
        array( 'wp-dom-ready' ),
        (string) filemtime( get_theme_file_path( $js ) ),
        array(
            'in_footer' => true,
            'strategy'  => 'defer',
        )
    );
}

Quatre choix comptent dans ce code. get_theme_file_uri() regarde d’abord dans le thème enfant, puis dans le parent, alors l’URL est bonne dans les deux cas. La version est la date de dernière modification du fichier : elle change à chaque déploiement qui touche le fichier. wp-dom-ready est un identifiant du cœur sur lequel votre script peut compter, et WordPress l’imprimera en premier. defer demande au fureteur de télécharger le fichier sans bloquer la page et de l’exécuter une fois le HTML analysé. L’article sur defer et async explique quand une autre stratégie convient mieux.

Un style et un script peuvent partager l’identifiant sh-slider, puisqu’ils vivent dans des registres séparés. WordPress ajoute -css et -js aux attributs id qu’il imprime.

Confirmez que les deux identifiants sont enregistrés :

wp eval 'do_action( "wp_enqueue_scripts" ); var_dump( wp_style_is( "sh-slider", "registered" ), wp_script_is( "sh-slider", "registered" ) );'
bool(true)
bool(true)

Un bool(false) veut dire que la fonction ne s’est jamais exécutée. Vérifiez que le thème enfant est actif avec wp theme list --status=active.

  1. Mettez en file seulement là où les fichiers servent. L’enregistrement ne coûte rien sur la page. C’est la mise en file qui imprime une balise. Ajoutez la condition à la fin de la même fonction, avant son accolade fermante :
    if ( is_front_page() ) {
        wp_enqueue_style( 'sh-slider' );
        wp_enqueue_script( 'sh-slider' );
    }

Récupérez la page d’accueil et une page intérieure :

curl -s https://example.com/ | grep -E "id=.sh-slider-(css|js)"
curl -s https://example.com/about/ | grep -cE "id=.sh-slider-(css|js)"

Exemple de sortie :

<link rel='stylesheet' id='sh-slider-css' href='https://example.com/wp-content/themes/sh-child/assets/css/slider.css?ver=1793152814' media='all' />
<script src="https://example.com/wp-content/themes/sh-child/assets/js/slider.js?ver=1793149207" id="sh-slider-js" defer data-wp-strategy="defer"></script>
0

Deux balises sur la page d’accueil et un compte de 0 sur la page intérieure : c’est le résultat voulu. Si la page d’accueil n’affiche rien, videz le cache de pages et récupérez-la de nouveau, car une copie du HTML en cache date d’avant votre changement.

  1. Passez les valeurs PHP au script en JSON. Ajoutez ceci dans la fonction, juste après wp_register_script() :
    wp_add_inline_script(
        'sh-slider',
        'window.shSlider = ' . wp_json_encode(
            array(
                'delay'   => 5000,
                'restUrl' => esc_url_raw( rest_url( 'sh/v1/slides' ) ),
            )
        ) . ';',
        'before'
    );

wp_add_inline_script() imprime votre extrait à côté de la balise du fichier, et 'before' le place avant le fichier, pour que window.shSlider existe déjà quand slider.js s’exécute. Comme la valeur passe par wp_json_encode(), 5000 arrive en JavaScript sous forme de nombre. L’ancienne fonction wp_localize_script() en ferait la chaîne "5000"; gardez-la pour les chaînes traduites.

curl -s https://example.com/ | grep -A3 'id="sh-slider-js-before"'

Exemple de sortie :

<script id="sh-slider-js-before">
window.shSlider = {"delay":5000,"restUrl":"https:\/\/example.com\/wp-json\/sh\/v1\/slides"};
//# sourceURL=sh-slider-js-before
</script>

WordPress 6.9 et plus récent ajoutent la ligne sourceURL, qui nomme l’extrait dans les outils de développement du fureteur. Les versions 6.3 à 6.8 impriment la même balise sans elle.

  1. Chargez les fichiers d’administration sur un seul écran. admin_enqueue_scripts passe à votre fonction le suffixe du hook, soit le nom interne de l’écran d’administration en cours de construction. Si votre thème ou votre extension ajoute une page de réglages, journalisez ce suffixe une fois pour connaître le nom de votre écran :
add_action( 'admin_enqueue_scripts', 'sh_admin_assets' );

function sh_admin_assets( $hook_suffix ) {
    error_log( $hook_suffix );
}

Ouvrez votre page de réglages dans wp-admin, puis lisez le journal :

tail -n 1 wp-content/debug.log

Exemple de sortie :

[29-Oct-2026 08:47:19 UTC] settings_page_sh-options

Remplacez la ligne error_log() par une garde qui utilise cette valeur exacte, puis mettez en file :

    if ( 'settings_page_sh-options' !== $hook_suffix ) {
        return;
    }

    $css = 'assets/css/admin.css';
    wp_enqueue_style(
        'sh-admin',
        get_theme_file_uri( $css ),
        array(),
        (string) filemtime( get_theme_file_path( $css ) )
    );

Ouvrez tour à tour le tableau de bord et votre page de réglages, et affichez le code source de chacun. sh-admin-css ne doit apparaître que sur la page de réglages.

  1. Appliquez le même modèle dans une extension. Seules les fonctions de chemin changent. Dans le fichier principal de l’extension, plugins_url( 'assets/js/slider.js', __FILE__ ) construit l’URL et plugin_dir_path( __FILE__ ) . 'assets/js/slider.js' donne le chemin pour filemtime(). Préfixez chaque identifiant avec le slug de votre extension. Deux extensions qui enregistrent toutes deux un identifiant slider entrent en collision, et le deuxième enregistrement est ignoré sans avertissement. Refaites la vérification curl de l’étape 3 : les valeurs href et src commencent maintenant par https://example.com/wp-content/plugins/ suivi du dossier de votre extension.

Vérifier que ça fonctionne

Faites ces trois vérifications après un déploiement.

Chaque identifiant s’imprime une fois. Comptez les balises sur la page qui doit les contenir :

curl -s https://example.com/ | grep -oE "id=['\"]sh-slider-(css|js)['\"]" | LC_ALL=C sort | uniq -c
      1 id="sh-slider-js"
      1 id='sh-slider-css'

Un 2 sur l’une des lignes veut dire qu’une balise est encore codée en dur quelque part. Refaites le grep de l’étape 1 sur le thème parent et sur toute extension d’extraits de code.

La version suit le fichier. Mettez à jour la date du script avec touch, récupérez la page de nouveau et comparez la valeur ver= :

touch wp-content/themes/sh-child/assets/js/slider.js
curl -s https://example.com/ | grep -oE 'slider\.js\?ver=[0-9]+'

Le nombre doit être plus élevé que celui vu à l’étape 3. Si un cache de pages se trouve devant WordPress, videz-le d’abord.

Rien ne se plaint. Chargez la page d’accueil, votre écran de réglages et l’éditeur de blocs, puis lisez le journal :

grep -i 'should not be registered or enqueued' wp-content/debug.log | tail -n 3

Aucune sortie : c’est le signal de réussite. Ouvrez aussi la console de développement du fureteur sur la page d’accueil; elle ne doit afficher aucune erreur venant de slider.js.

Dépannage

Le journal dit que wp_enqueue_script a été appelée incorrectement. L’avis précise ensuite que les scripts et les styles ne doivent pas être enregistrés ni mis en file avant l’un des trois hooks d’inclusion. L’appel s’est exécuté avant que WordPress soit prêt, en général parce qu’il se trouve au premier niveau de functions.php ou d’un fichier d’extension. Déplacez-le dans une fonction attachée au hook de l’écran visé, comme à l’étape 2.

Le fichier renvoie une 404 dans un thème enfant. get_template_directory_uri() pointe toujours vers le thème parent, alors un fichier du thème enfant construit avec elle obtient le mauvais dossier. Utilisez get_theme_file_uri(), qui regarde d’abord dans l’enfant, ou get_stylesheet_directory_uri(), qui désigne toujours le thème actif.

Les fureteurs gardent l’ancien fichier après un déploiement. La version est probablement une chaîne fixe comme '1.0'. Elle vaut peut-être aussi false, ce qui ajoute la version du cœur de WordPress au lieu de la vôtre. Passez à filemtime() comme à l’étape 2. Si le nombre ver= a déjà changé dans le code source et que les visiteurs reçoivent encore l’ancien fichier, la copie périmée se trouve dans un cache de pages ou un CDN (réseau de diffusion de contenu), pas dans le fureteur. Videz cette couche.

La console dit qu’une fonction ou une variable n’est pas définie. Votre script s’est exécuté avant le code dont il a besoin. Ajoutez l’identifiant du fournisseur au tableau des dépendances, par exemple array( 'jquery' ) pour une extension jQuery, pour que WordPress l’imprime en premier. Si le nom manquant est votre propre objet window.shSlider, vérifiez que l’extrait a été ajouté avec 'before' et que son identifiant correspond exactement à celui du script.

Le fichier se charge partout, ou nulle part. Les balises conditionnelles comme is_front_page() et is_singular() n’ont de réponse qu’une fois la requête analysée par WordPress. Dans wp_enqueue_scripts, elles fonctionnent. Dans une fonction accrochée à init ou à plugins_loaded, elles renvoient toujours false. Gardez la condition dans la fonction d’inclusion.

Quand ce n’est pas la bonne approche

Si le fichier appartient à un bloc personnalisé, déclarez-le dans le block.json du bloc avec style, editorScript ou viewScript. WordPress le charge alors seulement sur les pages où le bloc apparaît, sans condition à maintenir. Le flux de développement de blocs montre cette configuration.

Si votre JavaScript est écrit en modules ES qui utilisent import, enregistrez-le avec wp_register_script_module() et wp_enqueue_script_module(), offerts depuis WordPress 6.5. Les fonctions de script classiques impriment une balise de script ordinaire, et le fureteur refusera une instruction import à l’intérieur.

Si le but est d’empêcher les fichiers d’une extension de se charger là où ils ne servent pas, il s’agit de retirer des fichiers de la file, pas d’en ajouter. L’article pour retirer le CSS et le JavaScript inutilisés explique comment trouver l’identifiant et le retirer sans risque.

Quelques petits changements de style n’ont souvent pas besoin de fichier du tout. Le panneau CSS additionnel de l’outil de personnalisation dans un thème classique, ou Styles > CSS additionnel dans l’éditeur de site d’un thème de blocs, les garde là où la prochaine personne ira les chercher. La référence officielle de wp_enqueue_script liste chaque argument quand vous avez besoin des cas limites.

Un WordPress qui rapporte vraiment mérite un opérateur — Stack Harbor opère cette pile sous WordPress Entreprise ; réservez une consultation d’infrastructure.