Contenu principal

Commentaires conditionnels pour JS dans WordPress

Cela fait plusieurs années qu’il est demandé qu’une fonctionnalité plutôt basique soit ajoutée dans le cœur de WordPress, celle de pouvoir ajouter des commentaires conditionnels aux balises <script>. Surtout que cela fait longtemps qu’il est possible de le faire pour les balises <link> de nos fichiers CSS. Sachez qu’il est déjà possible de le faire avec peu de code. Je vais donc vous montrer ma méthode.

EDIT : depuis WordPress 4.2 (avril 2015), ceci n’est plus nécessaire, car ENFIN inclus nativement.

Nous allons utiliser une méthode similaire à celle employée pour les styles CSS, c’est à dire ajouter un paramètre 'conditional'.
Tout d’abord, comment ajouter ce paramètre ? Un exemple :

12345678

add_action( 'init', 'sf_init_scripts' );

function sf_init_scripts() {
	global $wp_scripts;

	wp_enqueue_script( 'selectivizr', get_template_directory_uri() . 'js/selectivizr.min.js', array( 'jquery' ), '1.0.2', true );
	$wp_scripts->add_data( 'selectivizr', 'conditional', 'lt IE 9' );
}

C’est plutôt simple, mais perso, j’aime bien me faire des petites fonctions qui me facilitent la vie :

010203040506070809101112

if ( ! function_exists('sf_conditional_script') ):
function sf_conditional_script( $script, $condition = 'lt IE 9' ) {
	return $GLOBALS['wp_scripts']->add_data( $script, 'conditional', $condition );
}
endif;

add_action( 'init', 'sf_init_scripts' );

function sf_init_scripts() {
	wp_enqueue_script( 'selectivizr', get_template_directory_uri() . 'js/selectivizr.min.js', array( 'jquery' ), '1.0.2', true );
	sf_conditional_script( 'selectivizr' );
}

Bien, il ne reste plus qu’à imprimer la balise <script> enrobée de son commentaire.
Il y a maintenant deux façons possibles de réaliser cela. La première, que voici, est un peu « hacky ».

010203040506070809101112

add_filter( 'script_loader_src', 'sf_conditional_scripts', PHP_INT_MAX, 2 );

function sf_conditional_scripts( $src, $handle ) {
	global $wp_scripts;

	if ( $src && ! $wp_scripts->do_concat && $conditional = $wp_scripts->get_data( $handle, 'conditional' ) ) {
		echo "<!--[if $conditional]><script type='text/javascript' src='$src'></script><![endif]-->\n";
		return false;
	}

	return $src;
}

En fait on utilise un filtre qui n’est pas fait pour cet usage : on filtre l’url du script, on echo la balise, et on retourne false. L’astuce consiste ici en ce return false;, qui fait que WordPress n’imprimera pas ensuite SA balise <script>. Petit détail, cette méthode ne fonctionne pas si $wp_scripts->do_concat est vrai, ce qui ne devrait pas poser de problèmes puisque jusque là je n’ai jamais rencontré cette configuration en front-end.

La seconde façon de faire est quasi-identique à la première. La différence est que l’on va utiliser un filtre dédié à ce genre de modification. Mais dans ce cas, pourquoi parler de la première méthode s’il existe un filtre dédié ? Parce que ce filtre est tout nouveau, il vient d’apparaitre dans la version 4.1 de WordPress. Petit bout de code choisi dans wp-includes/class.wp-scripts.php, méthode WP_Scripts::do_item() :

137138139140141142143144145146147148149150151152153154

/** This filter is documented in wp-includes/class.wp-scripts.php */
$src = esc_url( apply_filters( 'script_loader_src', $src, $handle ) );

if ( ! $src )
	return true;

$tag = "<script type='text/javascript' src='$src'></script>\n";

/** 
 * Filter the HTML script tag of an enqueued script.
 *
 * @since 4.1.0
 *
 * @param string $tag    The `<script>` tag for the enqueued script.
 * @param string $handle The script's registered handle.
 * @param string $src    The script's source URL.
 */
$tag = apply_filters( 'script_loader_tag', $tag, $handle, $src );

Et voici le résultat :

0102030405060708091011

add_filter( 'script_loader_tag', 'sf_conditional_scripts', PHP_INT_MAX, 3 );

function sf_conditional_scripts( $tag, $handle, $src ) {
	global $wp_scripts;

	if ( $tag && ! $wp_scripts->do_concat && $conditional = $wp_scripts->get_data( $handle, 'conditional' ) ) {
		return "<!--[if $conditional]><script type='text/javascript' src='$src'></script><![endif]-->\n";
	}

	return $tag;
}

Comme vous le voyez, cela revient au même.

Dernier détail, ici on ne gère pas les commentaires conditionnels qui sont sous la forme suivante :

1

<!--[if gt IE 8]><!--><script type='text/javascript' src='http://example.com/chemin/vers/jquery.poneys.rainbows.js'></script><!--<![endif]-->

Pour rappel, il s’agit ici d’un commentaire conditionnel où IE > 8 et les navigateurs autres que IE sont acceptés. D’ailleurs WordPress fait pareil pour les styles CSS.

See ya!

PS : le code est dispo dans un gist.