El minicarrito de la tabla de productos de WooCommerce no se actualiza
Cuando el minicarrito de WooCommerce no se actualiza tras pulsar Añadir al carrito en una tabla de productos, el fallo está en la visualización, no en el carrito. La tabla muestra Producto añadido al carrito (Product added to cart!) y la página del carrito lista el producto, pero el contador de la cabecera, el minicarrito del tema o el carrito lateral siguen mostrando el estado anterior hasta que se recarga la página. El producto está en el carrito; simplemente, el carrito del tema no se ha enterado. A continuación verás qué hace la tabla al añadir un producto, cómo averiguar en pocos minutos por qué tu carrito no reacciona y un script de pie de página que lo actualiza y abre los carritos laterales igual que los botones propios de WooCommerce.
Qué ocurre al añadir un producto desde la tabla
El botón Añadir al carrito (Add to cart) de la tabla usa el endpoint propio de WooCommerce, el mismo que utilizan los botones AJAX de la página de la tienda:
- El navegador envía una petición POST a
?wc-ajax=add_to_cartcon el ID del producto y la cantidad. WooCommerce añade el producto y responde con fragmentos del carrito actualizados: trozos de HTML para cada elemento del carrito de la página, identificados por su selector CSS, además de uncart_hash. - La tabla muestra su mensaje y lanza el evento JavaScript
woot-added-to-cartsobredocument. - Recarga su propia información del carrito (el panel del carrito de la tabla, los contadores de los botones) y lanza
woot-woo-cart-refreshed. - Dispara el evento
wc_fragment_refreshde WooCommerce, que pide al script de fragmentos del carrito de WooCommerce que vuelva a obtener los fragmentos y sustituya los elementos del carrito de la página.
El botón añadir seleccionados (add selected) de la cabecera de columna añade todos los productos marcados en una sola petición a admin-ajax.php y después ejecuta los pasos 3 y 4.
La diferencia con los botones de la página de la tienda está en el último paso. Esos botones toman los fragmentos de la respuesta, sustituyen directamente los elementos del carrito y anuncian la compra con el evento estándar de WooCommerce added_to_cart, que escuchan los plugins de carrito lateral y el bloque Mini-Cart de WooCommerce. La tabla, en cambio, se apoya en wc_fragment_refresh, y ese evento solo hace algo si el script de fragmentos del carrito (wc-cart-fragments) está en la página. Las versiones actuales de WooCommerce cargan ese script únicamente donde hace falta, por ejemplo con el widget clásico del carrito; muchos temas con su propio carrito en la cabecera lo cargan por su cuenta, otros no. Por eso el minicarrito permanece sin cambios en cuatro situaciones:
- el carrito del tema se actualiza mediante fragmentos, pero el script de fragmentos del carrito no se carga en la página de la tabla;
- el carrito lateral o el minicarrito reaccionan solo a
added_to_cart: se abren y se actualizan con un botón de la tienda, pero nunca con la tabla; - el contador del tema no es un fragmento en absoluto, así que solo cambia al recargar la página;
- una caché de páginas sirve HTML con un carrito antiguo, de modo que ni siquiera al recargar se ve el recuento correcto.
Encuentra la causa en cinco minutos
Abre la página de la tabla en una ventana privada, donde no tienes la sesión iniciada, y abre las herramientas de desarrollo (F12, o Cmd+Option+I en un Mac).
- Red (Network). Añade un producto desde la tabla y haz clic en la petición
?wc-ajax=add_to_cart. Si su respuesta contiene"error":true, el producto no se añadió y el problema está en el producto (existencias, límites de cantidad), no en el minicarrito. Si no, despliegafragments: sus claves, comodiv.widget_shopping_cart_content, son los elementos del carrito que WooCommerce y tu tema pueden actualizar. - Tu elemento del carrito. Haz clic derecho en el contador de la cabecera o en el minicarrito, elige Inspeccionar (Inspect) y compara su etiqueta y su clase con esas claves. Si no coincide ninguna, el elemento no es un fragmento: consulta más abajo la sección del filtro PHP.
- Consola (Console). Escribe
typeof wc_cart_fragments_paramsy pulsa Intro."undefined"significa que el script de fragmentos del carrito no está en la página, así quewc_fragment_refreshno hace nada. - Compáralo con la tienda. En la página de la tienda, añade un producto con el botón propio de WooCommerce. Si allí el minicarrito se actualiza o el carrito lateral se abre, pero tras la tabla no, tu carrito escucha
added_to_cart, que el script de pie de página de abajo se encarga de lanzar. - Recarga. Si el contador sigue mal tras recargar mientras la página del carrito muestra el producto, la página procede de una caché; consulta la sección sobre el almacenamiento en caché.
Actualizar el minicarrito y abrir el carrito lateral desde la tabla
Este script hace lo mismo que los botones de la página de la tienda. Cada vez que el carrito de la tabla se ha actualizado, obtiene los fragmentos de WooCommerce y sustituye los elementos del carrito de la página, por lo que no depende del script de fragmentos del carrito. Tras pulsar Añadir al carrito (Add to cart) o añadir seleccionados (add selected), además lanza added_to_cart con los fragmentos reales, de modo que los carritos laterales y el bloque Mini-Cart se actualicen y se abran según estén configurados.
/*
* Products tables: update the theme mini cart and side cart after products are
* added from a table. Add it to the site footer: a JavaScript snippet in a code
* snippets plugin, or the footer scripts field of your theme.
*/
(function ($) {
var announce = false;
function fragmentsUrl() {
if (typeof wc_add_to_cart_params !== 'undefined') {
return wc_add_to_cart_params.wc_ajax_url.toString().replace('%%endpoint%%', 'get_refreshed_fragments');
}
return '?wc-ajax=get_refreshed_fragments';
}
// One product added with a table's Add to cart button
document.addEventListener('woot-added-to-cart', function () {
announce = true;
});
// Several products added with the "add selected" button
document.addEventListener('click', function (e) {
var button = e.target.closest('.woot-add-to-cart-all-btn');
var table = button ? button.closest('table') : null;
if (table && table.querySelector('.woot-add-to-cart-check:checked')) {
announce = true;
}
}, true);
// The table cart was refreshed: on page load, after adding, removing or changing quantities
document.addEventListener('woot-woo-cart-refreshed', function () {
var opened = announce;
announce = false;
$.post(fragmentsUrl(), function (data) {
if (!data || !data.fragments) {
return;
}
$.each(data.fragments, function (selector, html) {
$(selector).replaceWith(html);
});
$(document.body).trigger('wc_fragments_refreshed');
if (opened) {
$(document.body).trigger('added_to_cart', [data.fragments, data.cart_hash, $()]);
}
});
});
})(jQuery);
Cómo se comporta:
- Los elementos del carrito se actualizan con cada cambio hecho a través de la tabla, incluidas las eliminaciones y los cambios de cantidad en la ventana emergente del carrito de la tabla. El evento
added_to_cart, y con él la apertura de un carrito lateral, solo se produce después de añadir productos. - El carrito de la tabla también se actualiza una vez al cargar la página, de modo que el script hace una petición de fragmentos adicional por cada página con una tabla. Así el minicarrito se mantiene correcto en las páginas que proceden de una caché.
- Algunos carritos laterales se abren únicamente mediante su propia función, no con
added_to_cart. Si el tuyo permanece cerrado mientras su contenido se actualiza, llama a esa función dentro del bloqueif (opened); la documentación del carrito lateral o su desarrollador te dirán cómo se llama.
Si prefieres enviar al comprador al carrito, la pestaña Opciones de la tabla incluye Después de añadir al carrito (After to cart adding) con Redirigir a la página del carrito (Redirect to the cart page) y Redirigir a la página de finalización de compra (Redirect to the checkout page). La tabla también puede mostrar su propio carrito, que siempre permanece sincronizado: activa Mostrar el carrito de la tienda (Show shop cart) en la misma pestaña, o coloca [woot_cart] en cualquier lugar de la página.
Cuando el contador del carrito del tema no es un fragmento
Un contador que no figura en la lista de fragments no puede actualizarse con ningún script, porque WooCommerce nunca envía HTML nuevo para él. Regístralo con el filtro woocommerce_add_to_cart_fragments de WooCommerce. Sustituye span.my-cart-count por la etiqueta y la clase del contador de tu tema, y conserva la misma clase en el HTML devuelto para que el elemento pueda volver a encontrarse la próxima vez:
/*
* Make the theme's cart counter a WooCommerce fragment, so it is refreshed
* after AJAX add to cart. Child theme functions.php or a code snippets plugin.
*/
add_filter('woocommerce_add_to_cart_fragments', function ($fragments) {
$fragments['span.my-cart-count'] = '<span class="my-cart-count">'
. esc_html(WC()->cart->get_cart_contents_count())
. '</span>';
return $fragments;
});
Esto ayuda tanto a los botones de la página de la tienda como a la tabla. Los temas y los constructores de páginas con un minicarrito complejo suelen registrarlo ya; si el suyo falta en la lista, pregunta al desarrollador del tema qué elemento usar.
Caché de páginas y optimización de scripts
Una caché de páginas almacena el HTML de una página, con el carrito de la cabecera incluido. Si el tema imprime su carrito en el HTML y la caché sigue sirviendo la versión generada para un carrito vacío, el contador es incorrecto tras cada recarga, mientras que la página del carrito, que los plugins de caché excluyen por defecto, es correcta. Dos medidas lo solucionan, y las cachés de tiendas WooCommerce necesitan ambas:
- No sirvas páginas en caché a los visitantes que tengan artículos en el carrito. WooCommerce establece para ellos las cookies
woocommerce_items_in_cartywoocommerce_cart_hash; la mayoría de los plugins de caché y de los alojamientos pueden omitir la caché cuando existen. WooCommerce enumera las páginas y las cookies que hay que excluir en Configuring caching plugins. - No almacenes nunca en caché las peticiones
?wc-ajax=niadmin-ajax.php. Una respuesta de fragmentos en caché pone el mismo carrito en la página de todos los visitantes.
Las funciones de optimización que retrasan, difieren o combinan JavaScript también pueden romper la cadena anterior: si el script del carrito del tema o los scripts del carrito de WooCommerce se ejecutan tarde o no se ejecutan, nada actualiza el carrito. Excluye jQuery, los scripts add-to-cart y cart-fragments de WooCommerce, el script del carrito de tu tema y la carpeta /wp-content/plugins/profit-products-tables-for-woocommerce/, y después vacía todas las cachés. Si al desactivar el plugin de caché u optimización (WP Rocket u otro similar) el minicarrito se corrige, repasa una por una sus opciones de caché y de JavaScript para encontrar el ajuste responsable en lugar de dejar el plugin desactivado.
Lista de comprobación
- La petición
?wc-ajax=add_to_cartresponde confragments, no con"error":true. - El carrito o el contador de tu cabecera coincide con una de las claves de los fragmentos, o está registrado con
woocommerce_add_to_cart_fragments. - El script de pie de página está en la página de la tabla y la consola del navegador no muestra errores.
- Las páginas no se sirven desde la caché a los visitantes con artículos en el carrito; las peticiones
wc-ajaxnunca se almacenan en caché. - Los scripts del carrito de WooCommerce, el script del carrito del tema y la carpeta del plugin están excluidos del retraso, el aplazamiento (defer) y la combinación de JavaScript.
Si el carrito sigue sin actualizarse, abre un tema en el foro de soporte de WOOT con el enlace de la página, el nombre de tu tema o del plugin de carrito lateral y las claves de los fragmentos de la respuesta de add_to_cart, y lo revisaremos.