Manejo de colisión de componentes jQuery
En el desarrollo de plugins, ¿cuál es la mejor práctica para prevenir colisiones de componentes jQuery en el front-end?
Por ejemplo, supongamos que incluyo el diálogo jQuery Apprise en un plugin que lo carga en el front-end para algo, pero otro plugin podría hacer lo mismo. Debido a que esto se carga y declara dos veces, o quizás uno está bifurcado y personalizado mientras que el mío no, obtenemos errores de Javascript en el frontend (asumo).
(Nota que estoy siguiendo la mejor práctica de usar la estrategia wp_register_script() y wp_enqueue_script() a través de un evento de acción wp_head() para cargar un componente jQuery en el frontend).

Mi sugerencia sería usar una combinación de aislamiento de código en una función anónima y verificar si jQuery ya está presente.
Aquí tienes un ejemplo:
(function() {
var jQuery; // tu variable jquery
// verificar si jQuery está presente y si tiene la versión que deseas
if (window.jQuery === undefined || window.jQuery.fn.jquery !== '1.8.3') {
// cargar la biblioteca jQuery desde las librerías alojadas en Google
var script_tag = document.createElement('script');
script_tag.setAttribute("type","text/javascript");
script_tag.setAttribute("src","http://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js");
// esperar a que cargue la biblioteca jQuery
if (script_tag.readyState) {
script_tag.onreadystatechange = function () { // versiones antiguas de IE
if (this.readyState == 'complete' || this.readyState == 'loaded') {
jqueryLoadHandler();
}
};
} else { // para otros navegadores
script_tag.onload = jqueryLoadHandler;
}
// Intentar encontrar el head, de lo contrario usar documentElement por defecto
(document.getElementsByTagName("head")[0] || document.documentElement).appendChild(script_tag);
} else {
// El sitio ya está usando el jQuery que deseas, así que simplemente apunta tu variable a ese jQuery
jQuery = window.jQuery;
main();
}
// tan pronto como jQuery se cargue
function jqueryLoadHandler() {
// Restaurar $ y window.jQuery a sus valores anteriores y almacenar el
// nuevo jQuery en nuestra variable local jQuery
jQuery = window.jQuery.noConflict(true);
// Llamar a la función principal del plugin
main();
}
// función principal del plugin
function main() {
jQuery(document).ready(function($) {
// Aquí puedes usar $ sin ningún problema
});
}
})(); // Llamamos inmediatamente a nuestra función anónima
De esta manera puedes usar jQuery sin problemas en tu plugin, incluso si otros plugins usaron jQuery sin wp_enqueue_script. Todas las variables y funciones que uses dentro de esta función anónima no interferirán con el resto de la página.
Quizás esto podría funcionar aún mejor si se integrara con wp_enqueue_script.
Puedes leer más sobre este enfoque de cargar jQuery dentro de una función anónima en http://alexmarandon.com/articles/web_widget_jquery/

El problema con el núcleo de jQuery es muy común y muchos plugins tienen varias formas de prevenirlo.
Cuando hablamos de plugins para jQuery existe otro problema pero puedes eliminarlo de manera similar.
En tu situación prefiero la solución común de agregar un interruptor de inclusión en la página de configuración de tu plugin - creo que esto es muy popular para plugins con el núcleo de jQuery, pero también puedes usarlo para plugins de jQuery.
Otra solución es escribir un script en js para verificar si el método extra de jQuery (del plugin) está definido, cuando no lo esté puedes incluir el plugin en tu script. Esta solución solo funcionará si agregas un hook para scripts con una prioridad muy baja. Se ejecutará después de otros plugins y esta condición funcionará.

La mejor práctica para encolar o registrar scripts es usar wp_register_script
y wp_enqueue_script
. Los plugins y temas que no usan estas funciones para agregar sus scripts no deberían utilizarse.
La razón es simple: con wp_register_script()
podemos obtener mucha información sobre los scripts registrados. Especialmente si una fuente determinada ya está registrada o no.
Escribí una clase simple para probar si una fuente ya está registrada. La clase puede desregistrar el script y registrar el nuevo script o omitir el nuevo script. Esta clase debería ser un punto de partida para tu propio desarrollo. ¡No es para entornos de producción!
¿Cómo funciona la clase?
La clase recupera un array con los scripts que deben registrarse. Luego compara los nombres de archivo (y solo los nombres de archivo) de cada script registrado con los nombres de archivo de los scripts que deben registrarse. Si el script/nombre de archivo no está registrado, su handle se agregará a un array y se registrará más adelante.
La clase se puede extender para comparar la ruta completa del script, la versión o lo que sea necesario para decidir si el script debe registrarse o no.
Un ejemplo simple
$my_scripts = array(
'foo' => array(
'src' => 'external/ressource/foo.js',
'deps' => array( 'jquery' ),
'version' => false,
'in_footer' => true
),
'bar' => array(
'src' => home_url( '/wp-admin/js/common.min.js' ),
'deps' => false,
'version' => false,
'in_footer' => true
),
'jquery' => array(
'src' => '//ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js',
'deps' => false,
'version' => '1.8.3',
'in_footer' => true
),
);
$safe_register = new Safe_Registering_Scripts( $my_scripts, true );
global $wp_scripts;
var_dump( $wp_scripts->registered['jquery'] );
Primero definimos un array con todos nuestros scripts para registrar. La clase recorrerá nuestros scripts y comparará si la fuente ya está registrada.
- El script
foo
siempre se registrará porque la fuente no está registrada. - El script
bar
nunca se registrará porque su fuente ya está registrada. - El script
jquery
es un caso especial. Ya existe un handle llamadojquery
, pero el segundo parámetro en la llamada a la clase indica que esta fuente de script debe reemplazarse por la nueva fuente.
Como puedes ver en el var_dump()
, la fuente del script jquery
fue reemplazada por la clase. Entonces, si extiendes la clase y ajustas la prueba (fuente, nombre de archivo js, versión, scripts encolados, etc.), podría ayudar a minimizar las colisiones de js.
