WordPress 3.3 est arrivé avec une nouvelle possibilité, celle de pouvoir « enqueue » un fichier javascript en milieu de page pour qu’il soit imprimé en fin de page. En quoi cette possibilité est bonne et pourquoi l’utiliser?
Ha bon ?
Je suis étonné de voir que cette nouvelle possibilité que nous apporte WordPress 3.3 n’ai pas fait plus de bruit que ça. Je l’ai bien vue parmi les changements importants dans le changelog de WP 3.3 mais c’est tout, pas d’article relatif sur un quelconque blog. Peut-être ai-je mal fouillé? Fort possible.
Jusque là nous pouvions « enqueue » les scripts à l’init, et indiquer si le script devait apparaitre dans le head ou le footer. Une fois le head passé, terminé, plus moyen d’ajouter un script proprement, il fallait passer par une technique « un peu bricolage » (en jouant avec la variable globale $wp_scripts) pour pouvoir dire en milieu de page, d’ajouter un script dans le footer.
Là c’est terminé, plus besoin de bricoler, la fonction wp_enqueue_script( ) peut être appelée à n’importe quel moment (enfin, tant que le footer n’est pas passé bien sûr). Comme je le disais en introduction, si l’on appelle wp_enqueue_script( )
après le head, le script sera imprimé dans le footer.
Mais encore
Donc que nous apporte cette possibilité?
Nous avons déjà tous eu affaire avec des plugins qui ajoutent leur(s) script(s) partout sur notre site, sur toutes les pages, même quand il n’est pas nécessaire, voire même dans l’administration.
Donc tous ceux soucieux du temps de chargement de leurs pages on certainement eu à utiliser un code similaire à celui-ci :
12345
add_action( 'wp_print_scripts', 'remove_annoying_scripts' );
remove_annoying_scripts() {
if ( !is_page('contact') )
wp_deregister_script( 'contact-form-7' );
}
Mais si demain ma page ne s’appelle plus contact mais contactez-moi? Retour dans le code pour modification. Et encore, si le site est destiné à un client, celui-ci n’est pas forcément au courant que renommer une page (ou son url) peut avoir des conséquences, et ne se rendra même pas compte que le javascript n’est plus disponible (d’ailleurs, sait-il au moins ce qu’est javascript? ;)). Au pays des bisounours il ne devrait même pas s’en soucier (rhôôôô).
A noter que je prend ContactForm7 comme exemple parce qu’il est très employé, je n’ai rien contre lui hein ;)
Bon, et donc, on fait quoi?
En premier c’est aux développeurs de plugins à utiliser cette nouvelle possibilité : ne plus employer wp_enqueue_script( )
sur le hook « init » lorsque ce n’est pas nécessaire, mais l’employer directement dans le code qui sera imprimé sur la page (un formulaire de contact par exemple, ou une galerie d’images, un diaporama, etc). Ainsi, le javascript ne sera imprimé que lorsqu’il est nécessaire.
Et pour ceux qui utilisent ces plugins qui mettent du javascript partout?
Là ça demande un peu de réflexion pour trouver le bon hook. Un exemple concret? J’en ai un avec ContactForm7 justement (ça tombe bien hein? ;))
En premier il faut empêcher le javascript d’être imprimé sur le site, mais sans se préoccuper de la page affichée cette fois.
12345
add_action( 'wp_print_scripts', 'remove_annoying_scripts' );
remove_annoying_scripts() {
if (function_exists('wpcf7_enqueue_scripts'))
wp_dequeue_script( 'contact-form-7' );
}
J’ai rajouté un test pour vérifier que le plugin est bien installé, mais ce n’est pas obligatoire. En l’état, aucun script de ce plugin ne sera imprimé.
A noter que j’ai utilisé wp_dequeue_script( ) qui ne va pas supprimer le script (disponible depuis WordPress 3.1), mais juste le laisser dans la file d’attente, en lui disant de rester au chaud pour une utilisation future (ou pas).
Phase deux, lancer wp_enqueue_script( )
seulement quand le formulaire est affiché :
Là je vais détourner un hook disponible dans le plugin, il s’agit du filtre « wpcf7_form_class_attr » qui permet d’ajouter ou de modifier les classes CSS du formulaire. Comme le filtre est utilisé au moment où le formulaire est affiché, c’est notre ouverture!
12345
add_filter('wpcf7_form_class_attr', 'cf7js_needed');
function cf7js_needed($class) {
wp_enqueue_script( 'contact-form-7' );
return $class;
}
Comme il s’agit d’un filtre, il y a forcément une valeur qui rentre, et une qui doit sortir. D’où la variable $class en paramètre, que l’on retourne à la fin pour ne pas que le formulaire se retrouve sans classe CSS.
Voilà, c’est tout!
Comme toujours, si on trouve les bons hooks, ça glisse tout seul :)
Hey, je suis pas passé à la version 3.3, c’est mort pour moi ?
Première réaction : Quoi!? Qu’est-ce que t’attends !?
Deuxième réaction : Bien sûr que non, je me suis penché sur la question.
Dans la même veine que mon article La nouvelle aide contextuelle de WordPress 3.3, j’ai développé une fonction (2 en fait) qui marchera à la fois pour WP 3.3+ (en utilisant tout simplement wp_enqueue_script( )
normalement) et pour les versions antérieures. Cet outil sera pratique à la fois pour un utilisateur de WP < 3.3 et pour des développeurs.
Je ne vais pas détailler tout ceci mais voici en gros ce qui va se passer pour WP < 3.3 :
En début de billet je vous parlais d'une méthode un peu bricolage qui consistait à jouer avec la variable $wp_scripts, qui contient toutes les références des scripts enregistrés, qu'ils soient imprimés ou non. Le défaut dont elle souffrait c'est la disparition des dépendances, c'est à dire imprimer tel script seulement si tel autre est imprimé, ou après tel autre script. Bref, tenir compte de la présence ou l'ordre de tout le monde.
Là, je vais utiliser la même méthode mais plus poussée. Ma fonction va mettre les scripts en file d'attente jusqu'au footer, et vont s'accumuler les uns après les autres. Arrivé le moment de les imprimer dans le footer, une autre fonction va se charger de réorganiser les scripts (et d'en ajouter si besoin) en fonction des dépendances respectives).
0001020304050607080910111213141516171819202122232425262728293031323334353637383940414243444546
/* Can enqueue scripts at mid-page for WP 3.3+ and < 3.3 */
if (!function_exists('sf_enqueue_script')) {
function sf_enqueue_script($handle = '', $src = false, $deps = array(), $ver = false, $in_footer = false) {
if ( $handle == '' )
return;
if ( function_exists('wp_trim_words') || !did_action('wp_print_scripts') ) { // WP 3.3+
wp_enqueue_script($handle, $src, $deps, $ver, $in_footer);
} else { // WP < 3.3
global $wp_scripts;
if ( ! is_a( $wp_scripts, 'WP_Scripts' ) ) {
if ( ! did_action( 'init' ) )
_doing_it_wrong( __FUNCTION__, sprintf( __( 'Scripts and styles should not be registered or enqueued until the %1$s, %2$s, or %3$s hooks.' ),
'<code>wp_enqueue_scripts</code>', '<code>admin_enqueue_scripts</code>', '<code>init</code>' ), '3.3' );
$wp_scripts = new WP_Scripts();
}
if ( $src ) {
$_handle = explode('?', $handle);
$handle = $_handle[0];
$wp_scripts->add( $handle, $src, $deps, $ver );
}
$wp_scripts->enqueue( $handle );
$wp_scripts->groups[$handle] = 1;
// Now we really add the script in the list of scripts to print in footer
$wp_scripts->in_footer[] = $handle;
// Many things could happen, we'll deal with dependencies just before print the scripts
add_action('wp_print_footer_scripts', 'sf_handle_scripts_deps');
}
}
}
/* Handle scripts dependencies just before print them (for WP all_deps($wp_scripts->in_footer);
$to_dos = array();
foreach ($wp_scripts->to_do as $key => $to_do) {
$to_dos[] = $to_do;
if ( !in_array($to_do, $wp_scripts->in_footer) && !in_array($to_do, $wp_scripts->done) ) {
$wp_scripts->enqueue( $to_do );
$wp_scripts->add_data( $to_do[0], 'group', 1 );
$wp_scripts->groups[$to_do] = 1;
}
unset($wp_scripts->to_do[$key]);
}
$wp_scripts->in_footer = $to_dos;
}
}
Voilà, la fonction sf_enqueue_script( )
est à utiliser de la même manière que wp_enqueue_script( )
, même paramètres toussa.
Le poney sur le gâteau
Tant que j’y suis, il y a aussi une autre fonction qui a été modifiée avec WP 3.3 et que j’ai adaptée pour les versions antérieures : wp_localize_script.
Depuis WP 3.3, wp_localize_script( )
accepte (enfin) le passage de tableaux multidimensionnels comme paramètre. J’ai donc crée une fonction qui aura le même comportement pour WP < 3.3, en utilisant json_encode()
:
01020304050607080910111213141516
if ( !function_exists( 'sf_localize_script' ) ) {
function sf_localize_script( $handle, $object_name, $l10n ) {
if ( ( is_array($l10n) && count($l10n) ) && !function_exists('wp_trim_words') ) { // $l10n is an array and WP < 3.3
if (isset($l10n['l10n_print_after']) && $l10n['l10n_print_after']) {
$new_l10n = array( 'l10n_print_after' => $l10n['l10n_print_after'] );
unset($l10n['l10n_print_after']);
$new_l10n['l10n_print_after'] = 'var '.$object_name.' = '.json_encode($l10n).';'."\n".$new_l10n['l10n_print_after'];
} else {
$new_l10n = array();
$new_l10n['l10n_print_after'] = 'var '.$object_name.' = '.json_encode($l10n).';';
}
wp_localize_script( $handle, $object_name.'0', $new_l10n );
} else
wp_localize_script( $handle, $object_name, $l10n );
}
}
Utilisation strictement identique à sa version originale.
Avec tout ceci, plus de problème de compatibilité par rapport aux versions de WordPress.
See ya!
Commentaires
Commentaire de Greg.
@13770 :
Il est difficile de faire des articles pour tous publics : débutants, intermédiaires ou experts. En l’occurrence mon article s’adresse à un public plutôt averti.
Pourquoi je n’ai pas expliqué ce qu’est « enqueue », les avantages, etc?
Parce que le sujet a déjà été abordé maintes fois sur le web, et je ne vois pas l’intérêt de reproduire ce que d’autres ont fait avant moi.
Bref, je vais quand même vous expliquer les quelques points qu’il vous manque pour une meilleure compréhension de ce billet, je ne suis pas un monstre quand même ;)
Le terme « enqueue » vient des fonctions WordPress wp_enqueue_script() et wp_enqueue_style() qui servent respectivement à mettre du javascript et des styles CSS dans une page du site. On peut le traduire par « mettre en file d’attente avant d’être inclus dans la page ».
La problématique :
Les plugins ont souvent besoin d’inclure du javascript (ou du CSS) dans nos pages… toutes nos pages le plus souvent. Mais cela ne veut pas dire que nous ayons besoins de ces scripts partout!
De plus, plus on ajoutera de fichiers CSS et javascript dans une page, plus elle sera longue à charger.
Le plugin que j’ai déjà pris en exemple plus haut, ContactForm7, un plugin de formulaire de contact, il fait comme tous les autres : il inclus son CSS et son javascript sur toutes les pages du site, sauf qu’on en a besoin que sur une seule page en général, la page contact par exemple.
Donc en général on rajoute un bout de code qui dira : « si on n’est pas sur la page contact, on ajoute pas le javascript ».
Là je propose une méthode qui me semble meilleure puisqu’on ne se préoccupe pas de la page concernée (page contact), à la place on ajoute le javascript uniquement quand le formulaire de contact est affiché, donc 100% efficace.
A bientôt
Commentaire de 13770.
Merci beaucoup l’explication est claire et même si je ne suis pas un expert je crois l’avoir comprise.
Amicalement
Commentaire de Hangsam.
Bonjour, je suis nouveau dans l’univers des blogues et tout ça me semble vraiment difficile. Ça fait maintenant des heures que je cherche comment introduire ce script javascript sur ma page d’accueil ou sur n’importe quelle autre page. Merci en espérant que vous allez pouvoir m’aider.
Commentaire de Grégory Viguier.
Bonjour.
Mettre ceci dans le fichier functions.php de votre thème. A adapter selon les besoins.
1234
get_stylesheet_directory_uri() retourne l’url du dossier de votre thème.
Voir wp_enqueue_script() pour les paramètres.