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 Rahe.
Hey,
J’en ai parlé ce dimanche sur mon blog oui ;)
http://blog.nicolas-juen.fr/2012/02/05/jquery-et-wordpress/
Ça fait bien partie d’une des fonctionnalités passée à la trappe lors de l’annonce de la 3.3, un peu comme is_main_query().
Vraiment pratique ta fonction de support pour les WP inférieurs :) ça peut toujours servir.
Commentaire de Greg.
En effet,
$query->is_main_query()
est aussi une de mes nouveautés préférées. Bon, par contre je n’ai pas cherché à en faire une version compatible WP < 3.3 ^^ Je crois même que ça ne doit pas être possible.Merci pour la visite :)
Commentaire de Rahe.
Je ne pense pas que ce soit vraiment possible pour
is_main_query()
effectivement…wp_editor()
est aussi vraiment pratique, on voit plus dans les blogs les mentions des choses visibles comme l’uploader etc.Vivement la 3.4 avec ses fichiers de trad admin/front séparés :)
Commentaire de Julio Potier @ BoiteAWeb.
Ultra puissant, même si je ne peux que dire « Passez à la 3.3.1 ! », le résultat est excellent pour le peu de code.
La recherche a dû être longue elle …
Ha oui, t’es pas développeur toi c’est vrai … #fake
Commentaire de Greg.
Oui le café a été très utile pour bien comprendre les rouages de tout ça et voir les différences avec le nouveau système.
En fait c’est tout bête, pour les scripts en footer ils ont repris le même mécanisme que pour le head, alors qu’il était complètement différent avant la 3.3 :)
Commentaire de Geoffrey @ Geoffrey.Crofte.fr.
Non non il n’est pas du tout développeur… #fakeplusplus
Encore un excellent article à garder sous le coude :)
Merci Greg !
Commentaire de Geoffrey @ Geoffrey.Crofte.fr.
J’ai déjà écrit quelques morceaux de code sur le Codex, faudrait penser à t’y mettre Greg :D
http://codex.wordpress.org/Plugin_API/Action_Reference
Commentaire de zet.
merci pour avoir fait ces recherches !
010203040506070809101112
Commentaire de Greg.
Salut zet.
Pourquoi pas en effet, mais ce n’est pas un truc que je ferais perso, ou que je conseillerais (d’ailleurs je n’ai jamais essayé, je ne sais pas si ça marche). Avoir une feuille de style en dehors du head ne me plait pas du tout :/
Je préfère largement ne pas utiliser le style par défaut du plugin et l’inclure dans la feuille de style du site.
Commentaire de zet.
en effet même si ca peut sembler bizarre, j’ai testé, et la css de wpcf7 est bien incluse dans le head …
mais je m’éloigne de ton sujet qui parle du js et non du moyen d’activer les plugins uniquement sur les pages où ils sont utilisés.
Commentaire de Greg.
Ha bon? En faisant ce que tu as mis plus haut le CSS est inclus dans le head?
Va falloir que je vois ça de plus près car ‘wpcf7_form_class_attr’ arrive après ‘init’, au moment où le formulaire est echo (ou alors j’ai raté un truc important), donc ça m’étonne.
Oui le sujet est au niveau du javascript, mais l’idée principale est bien sûr l’optimisation de tout ce que peut charger un plugin, donc tu ne t’éloigne pas vraiment ;)
Merci pour ton retour, je testerais ça :)
Commentaire de GeekPress.
Très bon tuto encore une fois. Je l’ai mis dans la newsletter de demain :)
Pour désactiver le CSS et le JS de Contact Form 7, je me permets de partager une astuce que j’ai publié il y a quelques semaines :)
Désactiver les fichiers CSS et Javascript de Contact Form 7.
Commentaire de Greg.
Salut mec.
Je connais cette méthode en effet, je l’utilise pour le CSS, mais pas pour le JS sinon il faut refaire le wp_enqueue_script( ) au complet avec les chemins et tout le tralala :]
Thx pour le complément d’info et la newsletter!
Commentaire de 13770.
Article sûrement très intéressant mais incompréhensible pour moi.
Pourquoi ne pas commencer par indiquer clairement, avec un exemple, à quoi ça peut servir. Nous sommes certainement très nombreux à ne pas savoir ce que signifie « enqueue » un fichier javascript ni à comprendre quel avantage il y a à le mettre en milieu de page.
Amicalement