Cómo agregar la etiqueta defer="defer" en los javascripts de plugins
No pude agregar la etiqueta defer en los javascripts del plugin. La prueba de velocidad de Google Developer me sugiere agregar la etiqueta defer en los javascripts de Contact Form 7.
Así es como Contact Form 7 incluye javascript en el encabezado.
add_action( 'wp_enqueue_scripts', 'wpcf7_enqueue_scripts' );
function wpcf7_enqueue_scripts() {
// jquery.form.js originalmente incluido con WordPress está desactualizado y obsoleto
// por lo que necesitamos anular su registro y volver a registrar la última versión
wp_deregister_script( 'jquery-form' );
wp_register_script( 'jquery-form', wpcf7_plugin_url( 'jquery.form.js' ),
array( 'jquery' ), '2.52', true );
$in_footer = true;
if ( 'header' === WPCF7_LOAD_JS )
$in_footer = false;
wp_enqueue_script( 'contact-form-7', wpcf7_plugin_url( 'scripts.js' ),
array( 'jquery', 'jquery-form' ), WPCF7_VERSION, $in_footer );
do_action( 'wpcf7_enqueue_scripts' );
}
¿Ahora cómo agregar la etiqueta defer="defer" en el código anterior?

A partir de WordPress 4.1 existe un filtro: script_loader_tag
. Puedes usarlo para encontrar el script correcto:
add_filter( 'script_loader_tag', function ( $tag, $handle ) {
if ( 'contact-form-7' !== $handle )
return $tag;
return str_replace( ' src', ' defer="defer" src', $tag );
}, 10, 2 );
Respuesta antigua
No hay un filtro dedicado disponible... al menos no puedo ver uno. Pero...
wp_print_scripts()
llama aWP_Scripts->do_items()
- que llama a
WP_Scripts->do_item()
- que usa
esc_url()
- que sí ofrece un filtro:
'clean_url'
.
Y aquí vamos:
function add_defer_to_cf7( $url )
{
if ( FALSE === strpos( $url, 'contact-form-7' )
or FALSE === strpos( $url, '.js' )
)
{ // no es nuestro archivo
return $url;
}
// ¡Debe ser una ', no "!
return "$url' defer='defer";
}
add_filter( 'clean_url', 'add_defer_to_cf7', 11, 1 );
Advertencia: no probado, solo una idea. :)
Actualización
He escrito y probado un plugin con este código.

¡Ese es un buen truco, y tan simple! Creo que también sería útil para agregar charset='utf-8' cuando sea necesario.

@henrywright WordPress añade '
en ambos lados de la cadena devuelta, un "
resultaría en HTML inválido.

Probablemente sea una buena idea en caso de que alguien quiera adaptar esto para que funcione con otros scripts, validar su uso solo en el front-end usando algo como if( ! is_admin() ){}
. Plugins populares como ACF podrían darte dolores de cabeza.

La respuesta aceptada es correcta, pero quería hacer algunas mejoras/actualizaciones para un caso más general, para cualquiera que, incluyendo mi yo futuro, llegue a esto mientras busca una respuesta. Para casos generales que no estén relacionados con el plugin contact-form-7, donde estés agregando el atributo defer a todos los scripts, probablemente quieras excluirlo de las páginas de administración, porque estas dependen de que los scripts se ejecuten en un orden específico. Además, para las páginas que no son de administración, querrás excluir jQuery, porque jQuery probablemente debería cargarse en el head antes que cualquier otra cosa. También, en lugar de manipular la cadena de texto del tag, una mejor manera de hacerlo sería cargarla en un objeto DOMDocument, manipularlo y luego convertirlo de vuelta a una cadena. Además, las versiones más recientes de PHP tienen verificación de tipos, por lo que probablemente deberías agregar los tipos de parámetros y retorno en tu llamada de función.
<?php
add_filter('script_loader_tag', function (string $tag, string $handle, string $src):string {
if (is_admin()) {
return $tag;
}
if (in_array($handle, array('jquery-core', 'jquery-migrate'))) {
return $tag;
}
$dom = new \DomDocument();
$dom->loadHTML($tag, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD);
$dom->getElementsByTagName('script')[0]->setAttribute("defer", "defer");
$tag = $dom->saveHTML();
return $tag;
}, 10, 3);
?>
