En el año 2008, jQuery transformó el desarrollo frontend. Simplificó las discrepancias entre motores de navegación y convirtió llamadas complejas de XMLHttpRequest en instrucciones limpias y legibles.
En 2026, mantener jQuery en los paquetes de scripts de un tema propio representa una deuda técnica prescindible. Los navegadores móviles modernos ejecutan directamente las especificaciones de ECMAScript contemporáneas. Forzar a los usuarios en dispositivos móviles a descargar, analizar y compilar entre 30KB y 87KB de código únicamente para alternar un menú de navegación desplegable supone un lastre que perjudica de forma directa los indicadores Core Web Vitals.
Esta guía técnica ofrece a los desarrolladores WordPress una metodología estructurada para refactorizar scripts propios basados en jQuery hacia JavaScript nativo sin alterar el funcionamiento de aquellas extensiones que continúen necesitando jQuery en el ámbito global. Entre los estándares oficiales referenciados se encuentran la API Fetch, la interfaz querySelector y la arquitectura de encolado de wp_enqueue_script.
¿Necesitan los navegadores modernos jQuery en 2026?
En el ecosistema web actual, las peculiaridades de motores antiguos han desaparecido por completo de los dispositivos de los usuarios:
document.querySelectorydocument.querySelectorAllgestionan de manera nativa todos los selectores CSS que anteriormente se consultaban mediante$().- Métodos estándar del DOM como
classList,closest(),matches()y la propiedaddatasetreemplazan las funciones de utilidad habituales. - La API nativa
fetch()combinada con promesas y async/await sustituye por completo a$.ajax()y$.getJSON(). - La API de animaciones web (Web Animations API) y las transiciones CSS aceleradas por hardware proporcionan movimientos fluidos sin necesidad de bucles de temporización en JavaScript.
- El núcleo de WordPress eliminó jQuery Migrate del encolado predeterminado del frontend en su versión 5.5. Aunque el núcleo incluye la librería por compatibilidad histórica, lo hace para sostener plugins de terceros, no porque una plantilla propia la requiera.
El propósito no es descartar librerías por principio, sino evitar sobrecargar de dependencias innecesarias los paquetes de código de tu proyecto.
Sustitución de selectores de jQuery por querySelector
Prescinde del uso de $() para consultar elementos del DOM en el código nuevo de tus temas:
// Sintaxis tradicional con jQuery
var $boton = $('.menu-toggle');
var $contenedor = $('#primary-navigation');
// JavaScript nativo moderno
const boton = document.querySelector('.menu-toggle'); // Primer elemento coincidente o null
const botones = document.querySelectorAll('.menu-toggle'); // Colección estática NodeList
const contenedor = document.getElementById('primary-navigation'); // Búsqueda optimizada por IDEs importante recordar que el objeto NodeList que devuelve querySelectorAll no es un envoltorio de jQuery. No se puede encadenar directamente un método como .addClass() sobre la lista. La forma correcta consiste en iterar los nodos mediante .forEach() o convertir la colección en un Array nativo:
// Iteración limpia sobre una lista de nodos
document.querySelectorAll('.menu-toggle').forEach((btn) => {
btn.setAttribute('aria-expanded', 'false');
});Asegúrate siempre de verificar que los elementos seleccionados individualmente no sean null antes de invocar métodos. Mientras que jQuery silenciaba las llamadas sobre selecciones vacías, JavaScript nativo lanzará una excepción TypeError si intentas acceder a propiedades de un elemento inexistente.
Sustitución de eventos click de jQuery por addEventListener
Sustituye los manejadores .on('click') y sus atajos por el método nativo addEventListener():
// Sintaxis tradicional con jQuery
$('.btn').click(function() {
console.log('Acción ejecutada');
});
// JavaScript nativo moderno
document.querySelectorAll('.btn').forEach((boton) => {
boton.addEventListener('click', () => {
console.log('Acción ejecutada');
});
});Implementación de delegación de eventos en vanilla JavaScript
En el caso de elementos inyectados dinámicamente en el documento (como listados con paginación infinita, filtros facetados en WooCommerce o fragmentos asíncronos de bloques), la delegación nativa se apoya en los métodos Element.matches() o Element.closest():
// Delegación de eventos sobre un contenedor padre estable
const contenedorProductos = document.getElementById('product-archive');
contenedorProductos.addEventListener('click', (evento) => {
const disparador = evento.target.closest('.quick-view-button');
if (disparador && contenedorProductos.contains(disparador)) {
evento.preventDefault();
abrirModalVistaRapida(disparador.dataset.productId);
}
});Vincular los escuchadores al contenedor estable más cercano en lugar de asignarlos indiscriminadamente a document evita ejecuciones redundantes del manejador en interfaces de gran complejidad.
Gestión de clases y estilos sin dependencias de jQuery
La propiedad nativa classList proporciona operaciones claras y eficientes para gestionar clases CSS:
// Sintaxis tradicional con jQuery
$el.addClass('activo').removeClass('oculto');
$el.toggleClass('abierto');
$el.css('display', 'block');
// JavaScript nativo moderno
el.classList.add('activo');
el.classList.remove('oculto');
el.classList.toggle('abierto');
el.style.display = 'block';Al gestionar estados visuales en la interfaz, prioriza siempre alternar clases CSS en vez de aplicar estilos en línea directamente. Esta práctica previene conflictos de especificidad con librerías como Tailwind y mantiene separadas las capas de presentación y comportamiento. Asimismo, classList.toggle(token, condicion) admite un segundo argumento booleano, permitiendo sincronizar el estado del DOM con respuestas del servidor en una sola línea.
Comunicaciones asíncronas modernas: sustituir $.ajax por fetch
Mientras que en 2010 $.ajax() ofrecía una solución indispensable ante las carencias del navegador, la API nativa fetch() se encuentra hoy integrada universalmente:
// Petición clásica con jQuery AJAX
$.ajax({
url: '/wp-json/custom/v1/datos',
method: 'GET',
success: function(respuesta) {
console.log(respuesta);
},
error: function(xhr, estado, error) {
console.error(error);
}
});
// Petición moderna en JavaScript nativo con async/await
async function obtenerDatosPersonalizados() {
try {
const respuesta = await fetch('/wp-json/custom/v1/datos', {
method: 'GET',
headers: {
'Accept': 'application/json'
}
});
if (!respuesta.ok) {
throw new Error(`Error en respuesta HTTP: ${respuesta.status}`);
}
const datos = await respuesta.json();
console.log(datos);
} catch (error) {
console.error('Fallo en la comunicación fetch:', error);
}
}Al consultar endpoints protegidos de la API REST de WordPress, envía las cabeceras de autenticación y el nonce de verificación correspondiente:
const respuesta = await fetch('/wp-json/wp/v2/posts', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-WP-Nonce': wpApiSettings.nonce
},
credentials: 'same-origin',
body: JSON.stringify({ title: 'Nuevo artículo' })
});En entornos específicos del editor de bloques Gutenberg, es preferible utilizar la utilidad oficial @wordpress/api-fetch (wp.apiFetch), que gestiona automáticamente los encabezados de autenticación y la resolución de rutas relativas.
Eliminación de los bloques document ready en temas modernos
El clásico contenedor $(document).ready() nació para posponer la ejecución de scripts hasta que el árbol del DOM estuviera construido. En el desarrollo web contemporáneo, las directivas de carga de scripts solucionan este aspecto de manera limpia desde el propio HTML:
<!-- Encolar scripts con el atributo defer carga el archivo de forma asíncrona y lo ejecuta tras parsear el HTML -->
<script src="/tema/assets/app.js" defer></script>Cuando los scripts se registran con el atributo defer o se insertan justo antes del cierre de la etiqueta </body>, los nodos del DOM ya se encuentran listos en el momento de la ejecución. Si necesitas garantizar la carga independientemente de la posición:
// Escuchador nativo para cuando el DOM está preparado
document.addEventListener('DOMContentLoaded', () => {
inicializarComponentesTema();
});Sustitución de animaciones por transiciones CSS modernas
Recurrir a métodos de jQuery como $el.fadeIn(), $el.slideUp() o $el.animate() obliga al hilo principal del navegador a recalcular estilos cuadro a cuadro mediante temporizadores.
Las arquitecturas modernas consiguen animaciones estables a 60 fotogramas por segundo delegando el trabajo en la GPU mediante transiciones CSS con propiedades aceleradas por hardware (opacity y transform):
/* Menú lateral eficiente acelerado por hardware */
.menu-desplegable {
transform: translateX(-100%);
transition: transform 0.25s cubic-bezier(0.16, 1, 0.3, 1);
will-change: transform;
}
.menu-desplegable.activo {
transform: translateX(0);
}
@media (prefers-reduced-motion: reduce) {
.menu-desplegable {
transition: none;
}
}Para secuencias programáticas complejas, utiliza la API nativa de animaciones web (element.animate()) en lugar de sobrecargar el proyecto con librerías pesadas.
Estrategia de migración paso a paso en temas de WordPress
Lleva a cabo la refactorización de manera ordenada para prevenir regresiones en las funcionalidades existentes:
- Auditar los scripts del tema: Busca referencias a
jQuery(,$(,$.ajaxy.on(en el código de tu tema. Concéntrate exclusivamente en tus propios archivos, ignorando carpetas de dependencias o plugins de terceros. - Reescribir la lógica de interfaz: Convierte las funciones del tema (menús móviles, acordeones, modales, pestañas o interruptores de modo oscuro) a módulos limpios de JavaScript nativo.
- Actualizar el registro de scripts en WordPress: En
functions.php, elimina'jquery'de la lista de dependencias de tus archivos encolados:// Antes: Forzando la carga innecesaria de jQuery wp_enqueue_script( 'scripts-tema', get_theme_file_uri( '/assets/app.js' ), array( 'jquery' ), '1.0.0', true ); // Después: Archivo nativo sin dependencias encolado con estrategia defer wp_enqueue_script( 'scripts-tema', get_theme_file_uri( '/assets/app.js' ), array(), '2.0.0', array( 'strategy' => 'defer', 'in_footer' => true ) ); - Verificar los flujos clave en pruebas: Comprueba en un entorno de staging la navegación móvil, formularios de contacto, modales y pasarelas de compra en WooCommerce.
- Medir el impacto en rendimiento: Evalúa la reducción de peso del paquete de scripts y el tiempo de respuesta del hilo principal mediante herramientas como Lighthouse y pruebas en dispositivos reales.
Evita desregistrar jQuery globalmente mediante wp_deregister_script('jquery') de entrada. Hacerlo provocará fallos inmediatos en plugins de terceros que requieran legítimamente la librería.
Razones arquitectónicas legítimas para conservar jQuery
WordPress carga jQuery en modo de compatibilidad mediante jQuery.noConflict(). Mantener la librería sigue siendo una decisión técnica plenamente justificada en circunstancias concretas:
- Una pasarela de pago indispensable o una extensión compleja de reservas depende de componentes antiguos de jQuery UI.
- El presupuesto en horas de desarrollo para reescribir un panel administrativo interno supera con creces cualquier beneficio perceptible para el visitante.
- El sitio web es en gran medida estático y ya obtiene calificaciones óptimas en Core Web Vitals sin requerir optimizaciones adicionales.
En caso de que mantener jQuery sea necesario, hazlo con criterio. Asegúrate de que los archivos propios del tema no sumen peso a la librería, permitiendo que esta se cargue únicamente en aquellas páginas donde las extensiones la soliciten explícitamente.
Errores habituales al migrar código desde jQuery
Presta atención a fallos recurrentes que suelen darse durante el proceso:
- Asumir que
$está disponible globalmente: En WordPress, el alias$no está garantizado en el ámbito global sin una función envolvente. - Refactorizar el código olvidando actualizar las dependencias: Reescribir los scripts a código nativo pero mantener
'jquery'enwp_enqueue_scriptsigue forzando la descarga del archivo en el navegador del usuario. - No evaluar
response.oken peticiones fetch: A diferencia de$.ajax, la APIfetch()no rechaza la promesa ante códigos de error HTTP como404o500. Es indispensable comprobarif (!response.ok). - Riesgos de XSS con innerHTML: Sustituir
.html()porinnerHTMLexige sanear las cadenas. El contenido procedente de usuarios debe asignarse mediantetextContento procesarse con librerías de desinfección como DOMPurify. - Ignorar el carácter estático de NodeList: Ten presente que
querySelectorAlldevuelve una instantánea estática. Los nodos que se agreguen posteriormente al documento no formarán parte de la colección a menos que utilices delegación de eventos.
Preguntas frecuentes sobre la migración a JavaScript moderno
¿Puedo anular el registro de jQuery globalmente en WordPress?
Solo si has verificado que absolutamente ningún plugin activo y ninguna herramienta administrativa la precisan. Retirarla de forma global suele ocasionar errores graves en extensiones heredadas. La recomendación es eliminar la dependencia en tu propio tema primero.
¿Qué sustituye formalmente a $.ajax en código nativo?
La API nativa fetch() con sintaxis async/await, o @wordpress/api-fetch en el entorno de Gutenberg. Recuerda suministrar las cabeceras de credenciales y el valor X-WP-Nonce en llamadas a endpoints protegidos de la API REST.
¿Cuándo es aconsejable mantener jQuery en el sitio?
Cuando extensiones comerciales esenciales dependen de ella o cuando rehacer desarrollos a medida en áreas privadas resulte inviable económicamente. Refleja siempre estas decisiones técnicas en el repositorio del proyecto.
¿Requiere la eliminación de jQuery un sistema de compilación?
No es obligatorio. Las operaciones básicas del DOM y los escuchadores de eventos se ejecutan de forma nativa en cualquier navegador moderno sin necesidad de transpiladores. Para proyectos modulares extensos, herramientas como @wordpress/scripts, Vite o ESBuild facilitan el empaquetado y la minificación.
Lista de verificación antes de pasar a producción
- Los scripts del tema propio no contienen referencias a
$ni ajQuery. - El código HTML servido a usuarios anónimos en páginas de aterrizaje no carga archivos de jQuery.
- Los menús desplegables, ventanas modales y buscadores operan con normalidad en dispositivos móviles.
- La consola del navegador no registra errores del tipo
jQuery is not defined. - Los informes de Core Web Vitals reflejan una reducción demostrable en el volumen de JavaScript transferido y en el tiempo de bloqueo de la CPU.
Gestión de dependencias de jQuery en Gutenberg, plugins y wp-admin
El editor de bloques y las extensiones modernas no requieren jQuery para la visualización pública en el frontend. Sin embargo, plugins basados en shortcodes o paneles de metadatos tradicionales siguen recurriendo a ella con frecuencia.
Tras completar la migración de tu tema, revisa las peticiones de red en páginas representativas: la portada, un artículo individual, una ficha de producto en tienda y el panel de administración. Deberás constatar que mientras wp-admin descarga jquery.min.js, las páginas públicas entregan código ligero y depurado sin la librería. Esta convivencia representa el equilibrio idóneo entre rendimiento y estabilidad operativa.
Medición de mejoras reales en Core Web Vitals
Suprimir 87KB de JavaScript sin comprimir genera mejoras medibles en teléfonos móviles de gama media. Aliviar la carga del procesador reduce la contención del hilo principal, lo que impacta de forma directa en el indicador Interaction to Next Paint (INP) y disminuye el Total Blocking Time (TBT).
Combinar la sustitución de jQuery con atributos modernos de carga diferida (defer o type="module") permite que la lógica de tu aplicación se ejecute sin bloquear el renderizado del contenido principal.
Próximos pasos en el desarrollo de tu tema
Inicia la refactorización abordando menús de navegación, modales y formularios asíncronos en las plantillas de tu tema. Mantén las extensiones de terceros sin tocar hasta que el código propio esté depurado.
Si requieres una auditoría de rendimiento web y Core Web Vitals para optimizar una plataforma corporativa en WordPress, puedes consultar nuestros servicios de desarrollador WordPress para recibir soporte técnico especializado.







