Publié sur Google Google
Clémence De Bastier profile picture
Clémence De Bastier
Google star 1Google star 2Google star 3Google star 4Google star 5Trustindex vérifie que la source originale de l'avis est Google.
Super prestataire, réactif et professionnel.
Publié sur Google Google
Service client weprecious profile picture
Service client weprecious
Google star 1Google star 2Google star 3Google star 4Google star 5Trustindex vérifie que la source originale de l'avis est Google.
Excellente expérience avec Aurelien et son Equipe. Tres réactifs et compétents. Je recommande.
Publié sur Google Google
Thom profile picture
Thom
Google star 1Google star 2Google star 3Google star 4Google star 5Trustindex vérifie que la source originale de l'avis est Google.
Je recommande les services d'Aurélien, disponible, pro et réactif !
Publié sur Google Google
Aude Sorey profile picture
Aude Sorey
Google star 1Google star 2Google star 3Google star 4Google star 5Trustindex vérifie que la source originale de l'avis est Google.
Merci pour votre aide. Rien ne fonctionnait et il ne faut pas s'étonner quand c'est un ami qui fait le site gratuitement, d'avoir des bugs ! Je recommande vos services avec plaisir à mes contacts.
Publié sur Google Google
Kevin Concha profile picture
Kevin Concha
Google star 1Google star 2Google star 3Google star 4Google star 5Trustindex vérifie que la source originale de l'avis est Google.
Aurelien a tout de suite compris mes attentes, et il m'a fait un site à la hauteur de mes exigences et est très minutieux dans les délais. J'ai d'autres sites à créer, c'est sans hésitation que je passerai par lui. Merci
Publié sur Google Google
Cédric APEP profile picture
Cédric APEP
Google star 1Google star 2Google star 3Google star 4Google star 5Trustindex vérifie que la source originale de l'avis est Google.
Rapide et efficace
Optimiser le chargement des Scripts et Styles sur WordPress : Adoptez l’Approche Idéale pour Votre Projet

Pour ajouter du JavaScript dans WordPress, ou une feuille CSS, on ne colle pas de balise <script> dans header.php : on déclare le fichier avec wp_enqueue_script() ou wp_enqueue_style(), dans une fonction accrochée au hook wp_enqueue_scripts, depuis le functions.php du thème (enfant) ou depuis une extension. WordPress imprime alors la balise au bon endroit, dans le bon ordre et une seule fois. Depuis WordPress 6.3, le cinquième argument accepte un tableau qui ajoute defer ou async : array( 'in_footer' => true, 'strategy' => 'defer' ).

Ce guide, à jour pour WordPress 7.1, couvre les paramètres, la différence avec wp_register_script, le chargement différé et conditionnel, les données vers JavaScript, les modules, le retrait d’un script et les erreurs fréquentes. Les exemples suivent les règles que j’applique en développement de thèmes WordPress sur mesure : code préfixé, conforme aux standards WordPress, et fichiers chargés uniquement là où ils servent.

Pourquoi passer par wp_enqueue_script plutôt qu’une balise script

Une balise écrite à la main échappe au gestionnaire de dépendances de WordPress. La file d’attente (« enqueue ») apporte :

  • un ordre garanti : un script est toujours imprimé après ceux dont il dépend ;
  • aucun doublon : un même identifiant (le « handle ») n’est chargé qu’une fois ;
  • un fichier que l’on peut retirer ou remplacer depuis un thème enfant ou une extension ;
  • un chargement différé sans casse : WordPress n’applique defer ou async que si l’ordre des dépendances le permet (voir plus bas).

Même le code d’un service tiers se met en file avec son URL complète, ou s’attache à un script avec wp_add_inline_script().

Les paramètres de wp_enqueue_script et wp_enqueue_style

wp_enqueue_script( $handle, $src, $deps, $ver, $args )

  • $handle : identifiant unique, à préfixer. Si un autre code a déjà enregistré ce handle, votre déclaration est ignorée.
  • $src : URL complète, avec get_theme_file_uri() ou plugins_url().
  • $deps : handles requis avant ce script ; jQuery seulement si votre code l’utilise.
  • $ver : ajouté à l’URL pour forcer le rechargement ; false ajoute la version de WordPress, null rien.
  • $args : depuis 6.3, in_footer, strategy, fetchpriority (6.9) et module_dependencies (7.0). Un booléen vaut in_footer.

wp_enqueue_style( $handle, $src, $deps, $ver, $media )

Le cinquième argument d’une feuille de style est le média : 'all' par défaut, 'print' ou une requête média. Ce n’est pas un réglage « pied de page » : y passer true, comme dans l’ancienne version de cet article, produit un attribut media invalide.

Paramètres de wp_enqueue_script et wp_enqueue_style (WordPress 7.1)
Position wp_enqueue_script wp_enqueue_style Par défaut
1 $handle $handle obligatoire
2 $src : URL du .js $src : URL du .css vide (handle déjà enregistré)
3 $deps : handles de scripts $deps : handles de feuilles array()
4 $ver $ver false (version de WordPress)
5 $args : in_footer, strategy, fetchpriority, module_dependencies $media : all, print, requête média array() (en-tête, bloquant) / all

Numéro de version et cache du navigateur

Trois options : une constante incrémentée à chaque livraison, la version du thème (wp_get_theme()->get( 'Version' )) ou filemtime(), qui change à chaque modification du fichier. filemtime() lit le disque à chaque page et émet un avertissement si le fichier manque : vérifiez son existence avant.

Charger un script et une feuille de style dans un thème ou une extension

Dans un thème ou un thème enfant

Voici l’exemple « simple » de l’ancienne version de cet article, corrigé : CSS dans assets/css/ et non plus dans /js/, pas de dépendance inutile à jQuery, script différé.

/**
 * Charge la feuille de style et le script principal du thème sur le front.
 */
function devwp_enqueue_assets() {
	$version = wp_get_theme()->get( 'Version' );

	wp_enqueue_style(
		'devwp-main',
		get_theme_file_uri( 'assets/css/main.css' ),
		array(),
		$version
	);

	wp_enqueue_script(
		'devwp-main',
		get_theme_file_uri( 'assets/js/main.js' ),
		array(),
		$version,
		array(
			'in_footer' => true,
			'strategy'  => 'defer',
		)
	);
}
add_action( 'wp_enqueue_scripts', 'devwp_enqueue_assets' );

Scripts et styles ont des registres séparés : le même handle sert aux deux. Le choix de la fonction de chemin compte si vous créez un thème enfant WordPress :

  • get_template_directory_uri() renvoie toujours le thème parent ;
  • get_stylesheet_directory_uri() renvoie le thème actif, donc l’enfant ;
  • get_theme_file_uri() cherche dans le thème actif puis se replie sur le parent : c’est la fonction que recommande le Theme Handbook.

Dans une extension

Dans le fichier principal d’une extension, l’URL se construit avec plugins_url() et __FILE__, le chemin disque avec plugin_dir_path(). La garde ABSPATH empêche l’appel direct du fichier.

<?php
/**
 * Plugin Name: DevWP Exemple
 */

defined( 'ABSPATH' ) || exit;

define( 'DEVWP_EXEMPLE_VERSION', '1.0.0' );

function devwp_exemple_enqueue_assets() {
	wp_enqueue_style( 'devwp-exemple', plugins_url( 'assets/css/front.css', __FILE__ ), array(), DEVWP_EXEMPLE_VERSION );
	wp_enqueue_script(
		'devwp-exemple',
		plugins_url( 'assets/js/front.js', __FILE__ ),
		array(),
		DEVWP_EXEMPLE_VERSION,
		array( 'strategy' => 'defer' )
	);
}
add_action( 'wp_enqueue_scripts', 'devwp_exemple_enqueue_assets' );

__FILE__ désigne le fichier en cours : appelé depuis un fichier rangé dans un sous-dossier, plugins_url() partirait de ce sous-dossier. Définissez plutôt une constante dans le fichier principal, par exemple avec plugin_dir_url( __FILE__ ). C’est la structure que j’utilise en développement d’extensions WordPress sur mesure ; pour aller plus loin, voyez comment se former au développement de plugins WordPress.

wp_register_script ou wp_enqueue_script ?

Ce que fait chaque fonction

wp_register_script() déclare un script sans rien imprimer. wp_enqueue_script() le met en file pour l’imprimer ; si vous lui passez une URL et que le handle n’existe pas, elle l’enregistre au passage, mais elle n’écrase jamais un enregistrement existant (il faut alors wp_deregister_script()). Même logique pour wp_register_style() et wp_enqueue_style().

Quand enregistrer sans charger

Enregistrez quand le script ne sert que sous condition (shortcode, bloc, modèle de page), quand il est chargé depuis plusieurs endroits, ou quand il sert de dépendance : il sera chargé automatiquement avec le script qui en dépend. Mettez directement en file quand il sert partout, ou que la condition se vérifie dans le hook.

// 1. Déclarer, sans charger.
function devwp_register_assets() {
	wp_register_script(
		'devwp-carte',
		get_theme_file_uri( 'assets/js/carte.js' ),
		array(),
		'1.2.0',
		array( 'strategy' => 'defer' )
	);
	wp_register_style( 'devwp-carte', get_theme_file_uri( 'assets/css/carte.css' ), array(), '1.2.0' );
}
add_action( 'wp_enqueue_scripts', 'devwp_register_assets' );

// 2. Charger seulement quand le shortcode est affiché.
function devwp_carte_shortcode( $atts ) {
	$atts = shortcode_atts( array( 'ville' => 'Orange' ), $atts, 'devwp_carte' );

	wp_enqueue_script( 'devwp-carte' );
	wp_enqueue_style( 'devwp-carte' );

	return '<div class="devwp-carte" data-ville="' . esc_attr( $atts['ville'] ) . '"></div>';
}
add_shortcode( 'devwp_carte', 'devwp_carte_shortcode' );

Le shortcode est rendu après wp_head : la feuille de style part alors en pied de page, d’où un bref affichage sans mise en forme. Pour l’éviter, détectez le shortcode dès le hook (voir le chargement conditionnel).

Le hook wp_enqueue_scripts n’est pas la fonction wp_enqueue_script

wp_enqueue_scripts, avec un « s », est une action, déclenchée par la fonction wp_enqueue_scripts(), elle-même accrochée à wp_head en priorité 1. On y place les scripts et les styles du site public. Les autres contextes ont leur hook : admin_enqueue_scripts (qui reçoit $hook_suffix : comparez-le, par exemple à 'settings_page_mon-extension', pour ne charger le script que sur votre page de réglages), login_enqueue_scripts, enqueue_block_editor_assets pour l’interface de l’éditeur et enqueue_block_assets pour le contenu, dans l’éditeur comme sur le site.

defer, async et pied de page : l’argument $args depuis WordPress 6.3

defer ou async ?

  • defer : téléchargé en parallèle, exécuté une fois le HTML analysé, dans l’ordre des balises. Le bon choix par défaut pour un script qui manipule la page.
  • async : exécuté dès qu’il est téléchargé, sans ordre garanti. À réserver aux scripts indépendants (mesure d’audience, widget tiers).
  • in_footer : imprimé avant </body>. Avec defer, l’emplacement compte moins. Avant WordPress 6.3, le tableau est lu comme true : le script part en pied de page, sans defer.

Comment WordPress respecte les dépendances

La stratégie demandée est une intention : WordPress calcule la stratégie « éligible » en parcourant les dépendances et les dépendants, pour ne jamais casser l’ordre d’exécution (voir la note officielle de WordPress 6.3). Un script différé dont un dépendant est bloquant redevient bloquant. Un script auquel est attaché un script en ligne en position 'after', la position par défaut de wp_add_inline_script(), est lui aussi traité comme bloquant : je l’ai vérifié dans le code de WordPress 7.1.3.

Pour contrôler, lisez le code source : data-wp-strategy indique la stratégie demandée, l’attribut defer ou async celle appliquée. Et n’ajoutez plus defer avec le filtre script_loader_tag : cette méthode ignore l’arbre des dépendances.

Depuis WordPress 6.9, la clé fetchpriority ('low', 'high' ou 'auto') règle la priorité de téléchargement : 'low' pour un script non essentiel, 'high' rarement. Une dépendance hérite de la priorité la plus haute de ses dépendants.

Et les feuilles de style ?

strategy ne concerne que les scripts. Pour les CSS, les leviers sont un média ciblé, qui ne bloque pas l’affichage, le chargement conditionnel, l’impression en ligne d’une petite feuille avec wp_style_add_data( $handle, 'path', $chemin ) (budget total de 40 000 octets par défaut depuis WordPress 6.9) et le CSS critique des extensions de performance, que je détaille pour optimiser les performances d’un site Avada.

Charger un script uniquement sur les pages qui en ont besoin

Quand je reprends un site, c’est souvent la première piste : des scripts de formulaire ou de diaporama chargés partout pour une seule page. Les balises conditionnelles (is_front_page(), is_page(), is_singular( 'product' )), has_block() et has_shortcode() s’utilisent directement dans la fonction accrochée au hook :

function devwp_conditional_assets() {
	if ( is_singular() && has_block( 'core/gallery' ) ) {
		wp_enqueue_script( 'devwp-lightbox' );
		wp_enqueue_style( 'devwp-lightbox' );
	}

	$current = get_post();
	if ( is_singular() && $current instanceof WP_Post && has_shortcode( $current->post_content, 'devwp_carte' ) ) {
		wp_enqueue_style( 'devwp-carte' ); // Imprimée dans le head : pas de contenu sans style.
	}
}
// Priorité 20 : après l'enregistrement des handles (priorité 10).
add_action( 'wp_enqueue_scripts', 'devwp_conditional_assets', 20 );

Pour vos blocs, déclarez viewScript, viewScriptModule et viewStyle dans block.json : WordPress les met en file au rendu du bloc, donc seulement sur les pages qui l’affichent.

Passer des données de PHP à JavaScript : wp_add_inline_script ou wp_localize_script

Selon la documentation officielle, wp_add_inline_script() est la bonne pratique pour transmettre des données ; wp_localize_script() est réservée aux chaînes à traduire, et convertit les valeurs simples du premier niveau en chaînes (true devient "1").

function devwp_enqueue_app() {
	wp_enqueue_script(
		'devwp-app',
		get_theme_file_uri( 'assets/js/app.js' ),
		array(),
		'1.0.0',
		array( 'strategy' => 'defer' )
	);

	$data = array(
		'restUrl' => esc_url_raw( rest_url( 'devwp/v1/' ) ),
		'nonce'   => wp_create_nonce( 'wp_rest' ),
	);

	// Position « before » : le script garde sa stratégie defer.
	wp_add_inline_script( 'devwp-app', 'const devwpApp = ' . wp_json_encode( $data ) . ';', 'before' );
}
add_action( 'wp_enqueue_scripts', 'devwp_enqueue_app' );
fetch( devwpApp.restUrl + 'favoris', {
	method: 'POST',
	headers: { 'X-WP-Nonce': devwpApp.nonce },
} );

Attention : un nonce expire après 12 à 24 heures, ce qui pose problème sur une page gardée plus longtemps en cache. Pour les textes du script, utilisez wp_set_script_translations().

Les modules JavaScript : wp_enqueue_script_module

Depuis WordPress 6.5, les modules ES (import / export) ont leur API : wp_register_script_module(), wp_enqueue_script_module(), wp_dequeue_script_module(). WordPress génère une « import map » : l’identifiant du module est le nom utilisé dans import. Une dépendance statique est préchargée ; une dépendance dynamique ('import' => 'dynamic') n’est chargée que si le code l’importe (voir la note de WordPress 6.5).

function devwp_enqueue_modules() {
	wp_register_script_module( '@devwp/utils', get_theme_file_uri( 'assets/js/utils.js' ), array(), '1.0.0' );
	wp_register_script_module( '@devwp/graphique', get_theme_file_uri( 'assets/js/graphique.js' ), array(), '1.0.0' );

	$deps = array(
		'@devwp/utils',
		array(
			'id'     => '@devwp/graphique',
			'import' => 'dynamic',
		),
	);
	wp_enqueue_script_module( '@devwp/recherche', get_theme_file_uri( 'assets/js/recherche.js' ), $deps, '1.0.0' );
}
add_action( 'wp_enqueue_scripts', 'devwp_enqueue_modules' );

// Données transmises au module (WordPress 6.7 et plus).
function devwp_recherche_data( $data ) {
	$data['restUrl'] = esc_url_raw( rest_url( 'wp/v2/search' ) );
	return $data;
}
add_filter( 'script_module_data_@devwp/recherche', 'devwp_recherche_data' );

wp_localize_script() ne fonctionne pas avec les modules : depuis WordPress 6.7, le filtre script_module_data_{$module_id} imprime les données en JSON, que le module lit ainsi :

import { formaterDate } from '@devwp/utils';

let data = {};
const conteneur = document.querySelector( 'script[id="wp-script-module-data-@devwp/recherche"]' );
if ( conteneur instanceof HTMLScriptElement ) {
	try {
		data = JSON.parse( conteneur.text );
	} catch {}
}
// data.restUrl contient l'URL transmise par PHP.

WordPress 6.9 ajoute aux modules un tableau $args (in_footer, pour les thèmes de blocs, et fetchpriority). WordPress 7.0 permet à un script classique d’importer dynamiquement des modules en les listant dans la clé module_dependencies de $args, à condition d’être en pied de page ou en defer.

D’où l’erreur « wp_enqueue_script type module not working » : passé à wp_enqueue_script(), un module est imprimé comme un script classique (« Cannot use import statement outside a module »), et un type="module" ajouté par filtre reste inconnu de WordPress : les modules qu’il importe ne sont ni ajoutés à l’import map ni préchargés. Utilisez l’API dédiée.

Retirer le script d’une extension : wp_dequeue_script

Une extension charge souvent ses fichiers sur toutes les pages. Sans la modifier, retirez-les là où ils ne servent pas, avec une priorité plus tardive que la sienne :

function devwp_dequeue_plugin_assets() {
	if ( is_page( 'contact' ) ) {
		return; // Le formulaire sert ici : on le garde.
	}
	// Remplacez par les handles réels, lus dans le code source de la page.
	wp_dequeue_script( 'extension-formulaire' );
	wp_dequeue_style( 'extension-formulaire' );
}
// Priorité 100 : après la mise en file par l'extension (souvent 10).
add_action( 'wp_enqueue_scripts', 'devwp_dequeue_plugin_assets', 100 );
  • Le handle se lit dans le code source : identifiant handle-js ou handle-css.
  • Script mis en file plus tard (rendu d’un shortcode) : agissez sur wp_footer avec une priorité inférieure à 20.
  • wp_deregister_script() supprime la déclaration, pour la remplacer sous le même handle.
  • Prudence : ne retirez pas jQuery ni un script du cœur sans raison, et testez en préproduction.

C’est la même démarche que pour modifier une extension sans toucher à son code : on agit par les hooks.

Organiser les ressources d’un projet plus important

Sur un thème sur mesure, je déclare les ressources dans un tableau, je les enregistre en boucle, puis je ne mets en file que ce que la page demande. Cet exemple corrige les méthodes « automatisée » et « expert » de l’ancienne version.

function devwp_register_theme_assets() {
	$assets = array(
		'devwp-base'   => array( 'type' => 'style', 'file' => 'assets/css/base.min.css' ),
		'devwp-menu'   => array( 'type' => 'script', 'file' => 'assets/js/menu.min.js' ),
		'devwp-slider' => array( 'type' => 'script', 'file' => 'assets/js/slider.min.js' ),
	);

	foreach ( $assets as $handle => $asset ) {
		$path = get_theme_file_path( $asset['file'] );
		if ( ! file_exists( $path ) ) {
			continue;
		}
		$url     = get_theme_file_uri( $asset['file'] );
		$version = (string) filemtime( $path );

		if ( 'script' === $asset['type'] ) {
			wp_register_script( $handle, $url, array(), $version, array( 'strategy' => 'defer' ) );
		} else {
			wp_register_style( $handle, $url, array(), $version );
		}
	}

	wp_enqueue_style( 'devwp-base' );
	wp_enqueue_script( 'devwp-menu' );
	if ( is_front_page() ) {
		wp_enqueue_script( 'devwp-slider' );
	}
}
add_action( 'wp_enqueue_scripts', 'devwp_register_theme_assets' );

file_exists() n’est pas une mesure de sécurité : il évite seulement une URL en 404. Avec @wordpress/scripts, la compilation produit un fichier index.asset.php qui renvoie les dépendances et un hash de version : lisez-le plutôt que de recopier ces valeurs.

function devwp_enqueue_build() {
	$asset_file = get_theme_file_path( 'build/index.asset.php' );
	if ( ! file_exists( $asset_file ) ) {
		return;
	}
	$asset = include $asset_file;

	wp_enqueue_script(
		'devwp-build',
		get_theme_file_uri( 'build/index.js' ),
		$asset['dependencies'],
		$asset['version'],
		array( 'strategy' => 'defer' )
	);
}
add_action( 'wp_enqueue_scripts', 'devwp_enqueue_build' );

Pour garder ce code homogène, configurez les WordPress Coding Standards dans VS Code ou PhpStorm.

Pourquoi un script ne se charge pas : les erreurs fréquentes

Quand wp_enqueue_script « ne marche pas », je commence par le code source : balise id="handle-js" absente, le problème est côté PHP ; fichier en 404, c’est le chemin. Puis je vérifie :

  1. Le hook : un appel trop tôt (avant init, par exemple au chargement d’une extension) est signalé en mode débogage ; après wp_footer(), rien n’est imprimé.
  2. Le chemin : get_template_directory_uri() dans un thème enfant, ou une barre oblique oubliée.
  3. Le handle : déjà pris par une autre extension, vos paramètres sont ignorés.
  4. Une dépendance non enregistrée : le script n’est pas imprimé ; depuis WordPress 6.9.1, un avertissement le signale en mode débogage.
  5. Le thème : sans wp_head() et wp_footer(), rien ne s’imprime.
  6. Un script exécuté trop tôt : dans le <head> sans defer, le DOM n’existe pas encore.
  7. jQuery : « $ is not a function » vient du mode noConflict ; déclarez 'jquery' en dépendance et utilisez jQuery( function( $ ) { … } ).
  8. Le cache : changez $ver, puis videz le cache de page et du CDN.
  9. Les optimisations : minification, regroupement ou report de l’exécution du JavaScript (comme l’option de WP Rocket) peuvent casser l’ordre d’exécution ; excluez le fichier pour vérifier.

Questions fréquentes sur wp_enqueue_script

Depuis WordPress 6.3, passez array( 'strategy' => 'defer' ) (ou async) en cinquième argument de wp_enqueue_script() ou de wp_register_script(). WordPress ne l’applique que si les dépendances le permettent, sans filtre script_loader_tag.

Le plus souvent, l’appel n’est pas fait sur le hook wp_enqueue_scripts, le chemin vise le thème parent au lieu du thème enfant, ou le handle est déjà pris. Une dépendance non enregistrée bloque aussi l’impression du script.

Entourez l’appel d’une balise conditionnelle dans la fonction accrochée à wp_enqueue_scripts : is_page(), is_singular(), has_block() ou has_shortcode(). Pour un bloc, déclarez le script dans block.json.

Elle fixe l’ordre d’exécution des fonctions accrochées au hook, pas l’ordre des fichiers dans la page, fixé par les dépendances déclarées. Une priorité tardive, comme 100, sert surtout à retirer le script d’une extension après qu’elle l’a mis en file.

Non, la clé strategy ne concerne que les scripts. Pour les CSS, jouez sur le média, le chargement conditionnel, l’impression en ligne avec wp_style_add_data() ou le CSS critique d’une extension de performance.

En résumé

Déclarez scripts et styles sur le hook wp_enqueue_scripts, avec la stratégie defer en cinquième argument, et ne chargez chaque fichier que là où il sert.

Besoin d’un thème dont les scripts sont chargés proprement ? Je réalise des thèmes WordPress sur mesure : présentez-moi votre projet.

Mis à jour en octobre 2026 pour WordPress 7.1, par un développeur WordPress freelance senior (14 ans d’expérience WordPress).

Faites tourner cet article !

À propos de l'auteur : Développeur WordPress freelance

Développeur WordPress freelance
Développeur WordPress Full Stack avec 14 ans d’expérience, j’accompagne les agences et les entreprises dans la création, la refonte et l’optimisation de leurs sites WordPress et boutiques WooCommerce. Développement sur mesure, maintenance, sécurité ou dépannage : je mets mon expertise au service de sites performants, fiables et adaptés à vos objectifs.