No hay nada que hunda más la conversión que un carrito que olvida que existe. Un comprador añade dos artículos, pulsa actualizar y —puf— carrito vacío. No van a depurar; se van. Mientras tanto, tú miras paneles que insisten en que el sitio está «saludable» porque HTTP 200 no es lo mismo que «la gente puede pagarte».
Este fallo casi nunca es «WooCommerce está roto». Normalmente es que el estado se pierde por caché, ámbito de cookies, almacenamiento de sesiones o enrutamiento multinodo. La buena noticia: puedes arreglarlo. La mala noticia: tienes que ser preciso, porque «limpiar todas las cachés» no es una estrategia; es una confesión.
Guía de diagnóstico rápido
Si haces esto en el orden correcto, encontrarás el cuello de botella rápido. Si lo haces en el orden equivocado, pasarás un día culpando a WooCommerce y una noche culpándote a ti mismo.
Primero: confirma si es pérdida de cookie/sesión o HTML cacheado
- Abre una ventana de incógnito, añade un producto al carrito, actualiza la página del carrito y la de pago.
- Revisa las cabeceras de respuesta en busca de aciertos de caché (CDN, Varnish, caché FastCGI de Nginx).
- Busca nuevas cookies después de añadir al carrito:
woocommerce_cart_hash,woocommerce_items_in_cart,wp_woocommerce_session_*.
Decisión: si el HTML está cacheado, necesitas exclusiones de caché y un comportamiento correcto de “vary”. Si las cookies no persisten, necesitas arreglar ámbito de cookies, HTTPS, SameSite, dominio o el almacenamiento de sesiones.
Segundo: verifica el enrutamiento multinodo y la salud del backend de sesiones
- ¿Estás detrás de un balanceador de carga? ¿Hay persistencia (stickiness)? ¿El almacenamiento de sesiones de WooCommerce está compartido (BD/Redis) entre nodos?
- ¿Usas Redis como caché de objetos? ¿Está perdiendo claves? ¿maxmemory está expulsando?
- ¿La latencia de la base de datos sube o hay tablas bloqueadas?
Decisión: si tienes varios nodos web y no hay almacenamiento de sesiones/objetos compartido (o está mal configurado), el carrito “desaparecerá al azar” según el nodo que atienda la petición.
Tercero: valida la tabla de sesiones de WooCommerce y el comportamiento del cron
- WooCommerce almacena los datos de sesión (por defecto) en la base de datos en una tabla dedicada.
- Las tareas de limpieza y el TTL importan. Una limpieza mal ajustada puede borrar sesiones vivas.
Decisión: si las sesiones se están eliminando o nunca se escriben, verás el carrito desaparecer de forma fiable al actualizar o tras un breve inactivo.
Una cita para mantener al equipo honesto (idea parafraseada): Eugene Rochal (círculos de operaciones/confiabilidad) popularizó la idea de que la fiabilidad viene de “hacer el estado explícito y observable”, no de la esperanza.
Qué ocurre realmente cuando el carrito “se vacía”
El carrito de WooCommerce no es magia. Es estado construido a partir de unos cuantos ingredientes:
- Cookies del lado cliente que identifican la sesión y llevan pistas (como el hash del carrito).
- Datos de sesión del lado servidor (a menudo en
wp_woocommerce_sessionso una tabla con prefijo personalizado) indexados por el identificador de sesión. - Renderizado HTML que no debe cachearse incorrectamente, porque es específico de cada usuario.
Cuando añades un artículo, WooCommerce escribe o actualiza los datos de sesión, establece cookies y luego renderiza los fragmentos del carrito/mini-carrito. El síntoma “carrito vacío al actualizar” suele significar una de estas cosas:
- El navegador nunca envía de vuelta la cookie de sesión (ámbito/flags de cookie incorrectos).
- El servidor no encuentra los datos de sesión (no escritos, purgados o almacenados en otro sitio).
- Una caché devuelve la versión de otra persona de la página (o una versión “sin carrito”) porque ignoró las cookies o los parámetros de consulta.
- Un nodo web distinto atiende la siguiente petición y no comparte el estado correctamente.
Hay variantes:
- El carrito solo se vacía en las páginas de carrito/pago: reglas de caché dirigidas a esas URL, o un plugin que “optimiza” esas rutas.
- El carrito se vacía solo tras iniciar sesión: migración de sesión entre invitado y usuario autenticado, desajuste de dominio de cookie, o caché que varía según cookies de login pero no según cookies de WooCommerce.
- El carrito se vacía solo en Safari/iOS: políticas de cookies más estrictas (SameSite, ITP), restricciones sobre cookies de terceros o flujos de redirección que fallan.
Broma corta #1: Si tu caché sirve el mismo carrito a todo el mundo, felicidades: has inventado una “experiencia de compra comunal”. No es del tipo por la que la gente paga.
Datos interesantes y contexto (lo que explica por qué esto sigue ocurriendo)
- WooCommerce dejó de depender de las sesiones PHP hace años para el estado del carrito; se apoya en su propio sistema de sesiones más cookies, porque escalar sesiones PHP es una trampa clásica en entornos multinodo.
- El caché de páginas en WordPress se volvió mainstream porque PHP+MySQL en hosting compartido era lento. El comercio electrónico es la primera carga de trabajo que castiga el reflejo de “cachearlo todo”.
- Varnish popularizó pensar que “los aciertos de caché son lo más importante” en los 2000. Para carritos, la “tasa de acierto” es una métrica de vanidad a menos que excluyas correctamente las páginas personalizadas.
- Los navegadores endurecieron las reglas de cookies en oleadas (SameSite por defecto, prevención de rastreo). Muchos bugs de carrito son en realidad “tus flags de cookie son de 2016”.
- Los CDN empezaron a cachear HTML agresivamente cuando el edge compute lo hizo atractivo. Eso es genial para blogs y terrible para checkout salvo que trates las cookies como parte de la clave de caché.
- Redis se convirtió en la herramienta de rendimiento por defecto en el ecosistema WordPress. Políticas de expulsión mal configuradas pueden borrar entradas de caché que el código asume que existen.
- WooCommerce usa actualizaciones AJAX de “fragmentos del carrito” para que el mini-carrito se actualice sin refrescar toda la página. Si esos endpoints AJAX están cacheados o bloqueados, la interfaz miente.
- Muchos plugins de “seguridad” reescriben cabeceras (especialmente flags de cookie y control de caché). La mitad está bien; la otra mitad es caos con una página de ajustes.
- Los balanceadores de carga facilitaron el escalado horizontal. También convirtieron la consistencia del estado en tu problema, por eso los carritos «desaparecen al azar» solo después de añadir el segundo nodo web.
Modos de fallo: sesiones, cookies, caché y almacenamiento
1) Cookies: dominio, ruta, HTTPS, SameSite y la trampa de redirección
Si el carrito se vacía inmediatamente tras actualizar, tu primer sospechoso es la cookie de sesión que no se devuelve. Causas comunes:
- HTTP/HTTPS mixto: el add-to-cart ocurre en HTTPS y luego una redirección o canonicalización envía al usuario a HTTP, perdiendo cookies marcadas como secure.
- Dominio de cookie equivocado:
example.comvswww.example.com. Uno establece cookies que el otro no envía. - Ruta de cookie demasiado estricta: cookie establecida para
/shoppero el carrito está en/cart. - Problemas de SameSite: redirecciones del proveedor de pago o flujos embebidos pueden comportarse distinto cuando las cookies no están marcadas correctamente.
- Cabeceras ya enviadas: advertencias PHP o salida pueden impedir establecer cookies de forma fiable. Sí, ese plugin antiguo todavía puede arruinarte el día.
2) Caché de página: servir HTML “vacío” obsoleto
La caché de página es genial hasta que no lo es. Las páginas de WooCommerce deben tratarse como personalizadas cuando el usuario tiene una sesión de carrito. Fallos típicos:
- URLs de carrito y checkout cacheadas (CDN, Varnish, FastCGI de Nginx, caché por plugin).
- La caché varía según la cookie de login de WordPress pero no según la cookie de sesión de WooCommerce. Invitados con carrito reciben la versión “sin carrito”.
- Endpoint de fragmentos del carrito cacheado (
?wc-ajax=get_refreshed_fragments), resultando en UI que muestra el mini-carrito vacío aunque el estado en servidor exista. - “Optimizar para móvil” cachea por separado pero no incluye cookies en la clave de caché, dividiendo el comportamiento entre dispositivos.
3) Caché de objetos: suposiciones de Redis/Memcached y evicción
La caché de objetos normalmente no guarda el carrito en sí, pero sí guarda cosas de las que WooCommerce depende: datos de cliente, productos, zonas de envío, fragmentos, transients y a veces helpers relacionados con sesiones. Problemas que verás:
- Evicción de Redis bajo presión de memoria: las claves desaparecen, el comportamiento se vuelve inconsistente y el carrito “a veces” se reinicia.
- Caché de objetos no persistente entre nodos: cada nodo tiene su propia caché local; el comportamiento difiere según el nodo que atienda.
- Drop-in defectuoso (
object-cache.php) que no soporta grupos correctamente o es incompatible con tu versión de WooCommerce.
4) Almacenamiento de sesiones: problemas en la tabla de la base de datos, limpieza y retraso de replicación
La tabla de sesiones de WooCommerce suele estar en MySQL/MariaDB. Está bien—hasta que no lo está. Puede estar lenta, bloqueada o en un réplica que va retrasada. Modos de fallo:
- Separación de lectura/escritura con retraso de réplica: add-to-cart escribe en el primario, actualizar lee de la réplica que no se ha sincronizado todavía, así la sesión parece vacía.
- Limpieza demasiado agresiva: sesiones borradas demasiado pronto por ajustes de TTL o un job programado que falla.
- Corrupción de tabla o índices faltantes: las búsquedas de sesión se vuelven lentas; timeouts pueden hacer que WooCommerce actúe como si no hubiera sesión.
5) Balanceadores de carga y WordPress multinodo: síndrome “funciona en un nodo”
Clásico: añades un segundo servidor web y de repente los carritos desaparecen. Eso no es WooCommerce siendo caprichoso. Es que ejecutas una aplicación con estado como si fuera un sitio estático.
- No hay sesiones pegajosas más almacenamiento local para algo que debería compartirse.
- Salts/keys diferentes entre nodos, rompiendo la validación de cookies y provocando que las sesiones sean rechazadas.
- Diferentes versiones de plugins entre nodos (sí, ocurre) que conducen a comportamiento inconsistente de cookies/sesiones.
6) Almacenamiento y sistema de ficheros: las sesiones no son la única ruta de escritura
Aunque las sesiones de WooCommerce están respaldadas en BD por defecto, tu entorno sigue escribiendo en disco: logs, ficheros de caché, a veces cachés de plugins. Un disco lleno o un sistema de ficheros en solo lectura puede crear síntomas de “carrito vacío” indirectamente (por ejemplo, plugins que fallan silenciosamente, base de datos que no puede escribir, PHP incapaz de crear ficheros temporales).
Tareas prácticas: comandos, salidas y decisiones (12+)
Estas son las tareas que realmente ejecuto en producción. Cada una tiene: comando, salida típica, lo que significa y la decisión que tomas.
Task 1: Confirmar comportamiento de caché en la página del carrito (cabeceras)
cr0x@server:~$ curl -I https://shop.example.com/cart/
HTTP/2 200
date: Sat, 27 Dec 2025 10:22:11 GMT
content-type: text/html; charset=UTF-8
cache-control: public, max-age=3600
age: 842
x-cache: HIT
via: 1.1 varnish
Qué significa: Tu HTML del carrito se está cacheando públicamente y sirviendo desde caché. Eso es una causa directa de “carrito vacío tras actualizar” para algunos o todos los usuarios.
Decisión: Desactiva la caché para /cart, /checkout y /my-account en todos los niveles (plugin de caché, proxy inverso, CDN). También asegúrate de que la caché varíe según las cookies de WooCommerce para las páginas que deben ser dinámicas.
Task 2: Comprobar si las cookies de WooCommerce se establecen tras añadir al carrito
cr0x@server:~$ curl -I -c /tmp/cookies.txt -b /tmp/cookies.txt "https://shop.example.com/?add-to-cart=123"
HTTP/2 302
date: Sat, 27 Dec 2025 10:23:04 GMT
set-cookie: wp_woocommerce_session_9c1b2a3d4e5f6g7h=1%7C%7C1735300000%7C%7C1735296400%7C%7C0f...; expires=Mon, 29 Dec 2025 10:23:04 GMT; Max-Age=172800; path=/; secure; HttpOnly; SameSite=Lax
set-cookie: woocommerce_items_in_cart=1; path=/; secure; SameSite=Lax
set-cookie: woocommerce_cart_hash=8c4f...; path=/; secure; SameSite=Lax
location: https://shop.example.com/cart/
Qué significa: Se están estableciendo cookies con path=/ y secure. Eso es bueno. Si no las ves, el carrito no persistirá.
Decisión: Si faltan cookies, inspecciona advertencias/salida de PHP, la configuración de dominio de cookies y las redirecciones HTTPS. Si las cookies existen pero no regresan, tienes un problema de política de navegador o desajuste de dominio.
Task 3: Verificar desajuste de dominio de cookie vía cookies en la respuesta
cr0x@server:~$ curl -I https://www.shop.example.com/cart/
HTTP/2 200
date: Sat, 27 Dec 2025 10:24:01 GMT
set-cookie: wp_woocommerce_session_9c1b2a3d4e5f6g7h=...; path=/; secure; HttpOnly; SameSite=Lax
Qué significa: Si tus usuarios aterrizan tanto en shop.example.com como en www.shop.example.com, probablemente estás estableciendo cookies separadas para cada host. Los usuarios “perderán” carritos durante redirecciones o al navegar entre nombres de host.
Decisión: Elige un host canónico, redirige el otro y haz que home/siteurl en WordPress coincidan. Evita configuraciones de “a veces www”.
Task 4: Detectar FastCGI cache en Nginx para carrito/checkout
cr0x@server:~$ curl -I https://shop.example.com/checkout/ | egrep -i "x-cache|x-fastcgi-cache|cache-control|set-cookie"
cache-control: max-age=600
x-fastcgi-cache: HIT
Qué significa: Nginx está sirviendo HTML cacheado del checkout. Eso puede aplastar carritos a “vacío” o hacer que un usuario vea el estado de otro (lo cual es peor).
Decisión: Excluye los endpoints de WooCommerce de la caché FastCGI y asegura que la clave de caché varíe según la cookie de sesión de WooCommerce donde corresponda.
Task 5: Comprobar que existe la tabla de sesiones de WooCommerce y tiene datos
cr0x@server:~$ mysql -e "SHOW TABLES LIKE '%woocommerce_sessions%';"
+--------------------------+
| Tables_in_wp (%sessions%)|
+--------------------------+
| wp_woocommerce_sessions |
+--------------------------+
Qué significa: La tabla existe. El siguiente paso es verificar escrituras y comportamiento de expiración.
Decisión: Si no existe, tienes una instalación/migración rota, o un plugin cambió el handler de sesiones. Arregla eso antes de tocar la caché.
Task 6: Confirmar que las sesiones se escriben y no expiran instantáneamente
cr0x@server:~$ mysql -e "SELECT session_key, session_expiry FROM wp_woocommerce_sessions ORDER BY session_expiry DESC LIMIT 3;"
+----------------------------------+---------------+
| session_key | session_expiry |
+----------------------------------+---------------+
| 9c1b2a3d4e5f6g7h | 1735300024 |
| 4aa02c0d1131c9b2 | 1735299980 |
| 1fbb9d3d8a2a4e1a | 1735299901 |
+----------------------------------+---------------+
Qué significa: Los timestamps de expiración parecen razonables (en el futuro). Si ves expiraciones en el pasado o solo una ventana pequeña, algo está purgando las sesiones demasiado agresivamente.
Decisión: Si la expiración es incorrecta, revisa ajustes de sesión de WooCommerce, el cron y cualquier job de limpieza personalizado. También comprueba la deriva del reloj del servidor.
Task 7: Comprobar separación lectura/escritura de BD (retraso de réplica)
cr0x@server:~$ mysql -e "SHOW SLAVE STATUS\G" | egrep "Seconds_Behind_Master|Slave_IO_Running|Slave_SQL_Running"
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
Seconds_Behind_Master: 18
Qué significa: El réplica va 18 segundos detrás. Si tus lecturas de datos de sesión van a la réplica, una actualización justo después de añadir al carrito puede devolver “sin sesión”, es decir, carrito vacío.
Decisión: No leas datos críticos de sesión/carrito desde réplicas. Ancla lecturas/escrituras de sesión de WooCommerce al primario o asegura consistencia de lectura tras escritura.
Task 8: Verificar si Redis está expulsando claves (inestabilidad de caché de objetos)
cr0x@server:~$ redis-cli INFO memory | egrep "used_memory_human|maxmemory_human|mem_fragmentation_ratio"
used_memory_human:1.92G
maxmemory_human:2.00G
mem_fragmentation_ratio:1.64
Qué significa: Redis está cerca de maxmemory con alta fragmentación. Si la evicción está habilitada, las claves pueden desaparecer bajo presión, causando comportamiento errático.
Decisión: Aumenta la memoria de Redis, ajusta la política de evicción, reduce la huella de caché o mueve el uso intensivo de transients a otro lado. No ejecutes estado crítico de e-commerce junto a una caché famélica.
Task 9: Confirmar política de evicción de Redis y contadores de evicción
cr0x@server:~$ redis-cli CONFIG GET maxmemory-policy
1) "maxmemory-policy"
2) "allkeys-lru"
cr0x@server:~$ redis-cli INFO stats | egrep "evicted_keys|keyspace_hits|keyspace_misses"
evicted_keys:48219
keyspace_hits:18022411
keyspace_misses:2401120
Qué significa: evicted_keys es distinto de cero y crece, lo que significa que Redis está borrando claves para hacer sitio. Si plugins o temas asumen que los objetos cacheados existen, obtendrás una UX inconsistente.
Decisión: Evita la evicción en cachés de producción solo si toleras que fallen las escrituras; normalmente es mejor dimensionar correctamente y asegurar que el estado crítico del carrito no esté solo en Redis.
Task 10: Comprobar que todos los nodos web comparten las mismas salts de WordPress
cr0x@server:~$ ssh web1 "grep -E \"AUTH_KEY|SECURE_AUTH_KEY|LOGGED_IN_KEY|NONCE_KEY\" -n /var/www/html/wp-config.php | sha256sum"
7f6b0a0b8b2a1b0c44d5d5f2d0a... -
cr0x@server:~$ ssh web2 "grep -E \"AUTH_KEY|SECURE_AUTH_KEY|LOGGED_IN_KEY|NONCE_KEY\" -n /var/www/html/wp-config.php | sha256sum"
2f1c7f0fd9d1c8e0ad0b3f1d9c... -
Qué significa: Los hashes difieren. Eso es malo. La validación de cookies y el comportamiento relacionado con auth/sesiones puede diferir por nodo.
Decisión: Haz wp-config.php consistente entre nodos (idealmente vía gestión de configuración). Reinicia PHP-FPM si es necesario. Luego vuelve a probar carritos.
Task 11: Comprobar la persistencia del balanceador y alternancia de backend
cr0x@server:~$ for i in {1..6}; do curl -sI https://shop.example.com/cart/ | awk -F': ' 'tolower($1)=="x-backend"{print $2}'; done
web2
web1
web2
web1
web2
web1
Qué significa: Las peticiones alternan entre nodos. Si el almacenamiento de sesión no está compartido o es inconsistente, los carritos pueden desaparecer al actualizar según el backend que atienda la petición.
Decisión: Implementa stickiness (curita a corto plazo) o corrige el estado compartido (la solución correcta a largo plazo). Para WooCommerce, la tabla de sesiones en BD compartida suele ser suficiente si las lecturas/escrituras son coherentes y la latencia está controlada.
Task 12: Verificar que PHP-FPM no esté descartando peticiones o agotando tiempo en escrituras de sesión
cr0x@server:~$ sudo tail -n 60 /var/log/php8.2-fpm.log
[27-Dec-2025 10:21:58] WARNING: [pool www] server reached pm.max_children setting (20), consider raising it
[27-Dec-2025 10:22:03] WARNING: [pool www] child 1934, script '/var/www/html/index.php' (request: "POST /?wc-ajax=add_to_cart") execution timed out (120.000 sec)
Qué significa: Estás saturando los trabajadores de PHP-FPM y agotando tiempo durante add-to-cart AJAX. Si la escritura falla, la siguiente actualización podría mostrar legítimamente un carrito vacío.
Decisión: Arregla la capacidad: aumenta pm.max_children si CPU/RAM lo permiten, optimiza consultas lentas y evita que plugins en segundo plano acaparen trabajadores.
Task 13: Revisar el log de acceso de Nginx para fragmentos de carrito o anomalías
cr0x@server:~$ sudo grep -E "wc-ajax=get_refreshed_fragments|wc-ajax=add_to_cart" /var/log/nginx/access.log | tail -n 5
203.0.113.10 - - [27/Dec/2025:10:23:05 +0000] "POST /?wc-ajax=add_to_cart HTTP/2.0" 200 1324 "-" "Mozilla/5.0"
203.0.113.10 - - [27/Dec/2025:10:23:06 +0000] "GET /?wc-ajax=get_refreshed_fragments HTTP/2.0" 200 4012 "-" "Mozilla/5.0"
Qué significa: El flujo normal está ocurriendo. Si ves bucles 301/302, 403s (WAF) o cabeceras de caché sospechosas en estos endpoints, el mini-carrito puede mentir.
Decisión: Excluye estos endpoints AJAX de la caché y asegura que tu WAF no los bloquee. No son opcionales para una UX sensata.
Task 14: Validar espacio en disco y sistema de ficheros de solo lectura (el sabotaje aburrido)
cr0x@server:~$ df -h /var /tmp
Filesystem Size Used Avail Use% Mounted on
/dev/nvme0n1p2 100G 99G 1.0G 99% /
tmpfs 16G 16G 0 100% /tmp
Qué significa: Te quedaste sin espacio. El espacio temporal lleno puede romper subidas, plugins de caché, procesamiento de imágenes y a veces operaciones relacionadas con sesiones dependiendo de la pila.
Decisión: Libera espacio ahora. Luego implementa monitorización y rotación de logs sensata. No dejes que “no hay espacio en el dispositivo” se disfrace de bug de WooCommerce.
Task 15: Comprobar cabeceras no-cache específicas de WooCommerce (deben existir en páginas sensibles)
cr0x@server:~$ curl -I https://shop.example.com/checkout/ | egrep -i "cache-control|pragma|expires"
cache-control: no-store, no-cache, must-revalidate, max-age=0
pragma: no-cache
expires: Wed, 11 Jan 1984 05:00:00 GMT
Qué significa: Estas cabeceras son saludables. Si ves public o un max-age largo, tu capa de caché puede estar ignorando la intención del origen o sobreescribiendo cabeceras.
Decisión: Haz que las capas de caché respeten las cabeceras del origen en carrito/checkout, o aplica reglas de bypass por ruta y por cookies.
Tres microhistorias corporativas desde el terreno
Microhistoria 1: El incidente causado por una suposición equivocada (la historia de “las réplicas están bien para lecturas”)
Tenían un diagrama de arquitectura limpio y una realidad desordenada. La pila era WordPress + WooCommerce detrás de un balanceador, base de datos dividida en primario para escrituras y réplica para lecturas. Funcionaba para páginas de blog y producto. Los gráficos se veían fantásticos. Todos chocaron las manos por la victoria de “escalar”.
Luego el carrito empezó a vaciarse. No siempre. Suficientemente a menudo como para hundir ingresos y crear tickets de soporte con el mismo tono que las quejas por maletas de aerolínea. El ingeniero de guardia hizo lo que hacen los de guardia: reinició PHP-FPM, purgó cachés y miró logs hasta que el café se volvió mecanismo de afrontamiento.
La causa raíz fue una suposición equivocada: “las lecturas de sesión son solo lecturas”. WooCommerce escribió datos de sesión en el primario al añadir al carrito, luego la página del carrito leyó de la réplica porque la consulta parecía una lectura. Con el retraso de replicación bajo carga, el registro de sesión no estaba ahí todavía. El sitio actuó como si tuviera amnesia, pero solo los primeros segundos después de un cambio.
La solución fue irritantemente simple y profundamente política: dejar de dirigir lecturas de la tabla de sesiones de WooCommerce a la réplica. Implementaron una regla para fijar esas consultas al primario. La conversión se recuperó inmediatamente. Nadie quiso hablar de eso en la siguiente revisión de arquitectura, porque hacía el diagrama menos elegante.
Lección: la consistencia de lectura tras escritura vence a la “separación limpia” cuando los clientes hacen clic en “Realizar pedido”.
Microhistoria 2: La optimización que salió mal (la campaña de “cachearlo todo”)
Una iniciativa de rendimiento pasó por la empresa como una tormenta bienintencionada. La directiva fue clara: aumentar la tasa de aciertos de caché. Alguien añadió reglas agresivas de caché en el proxy inverso y una configuración del CDN para cachear HTML de “páginas dinámicas” con un TTL corto. Hizo que las páginas de producto fueran rápidas. También hizo que la página del carrito fuera rápida—rápida siendo incorrecta.
Los clientes informaron que sus carritos se vaciaban al actualizar. Otros dijeron ver el recuento del carrito de otra persona en el header. Ese segundo síntoma convierte un bug en una reunión de incidente de seguridad. La causa raíz: la clave de caché no variaba según la cookie de sesión de WooCommerce. El CDN veía /cart/ como la misma página para todos.
El equipo intentó «purgar todo» cada hora. Intentaron bajar el TTL a 10 segundos. Intentaron añadir una cadena de consulta. Todo eso trataba un error de diseño de envenenamiento de caché como si fuera un problema de expiración. No lo era. Estaban cacheando HTML personalizado sin una clave de personalización.
La solución real fue poco glamorosa: evitar la caché para las páginas cart/checkout/account, y evitar la caché cuando existieran cookies de WooCommerce. Para todo lo demás, cachear normalmente. La tasa de aciertos bajó. Los ingresos subieron. ¿Qué métrica prefieres explicar al CFO?
Microhistoria 3: La práctica aburrida pero correcta que salvó el día (consistencia de configuración)
Otra organización tenía tres nodos web y la costumbre de “fixes en caliente”. Un ingeniero SSH en un nodo, tocaba wp-config.php y daba el día por terminado. El siguiente ingeniero hizo lo mismo en otro nodo. Con el tiempo, los nodos derivaron como continentes: salts diferentes, ficheros de plugins distintos, ajustes de PHP INI ligeramente distintos.
La pérdida de carrito parecía “aleatoria”. No lo era; era caos determinista. Los usuarios añadían al carrito, actualizaban, daban con un backend distinto y la cookie de sesión fallaba la validación. El sistema hizo lo que se le dijo: rechazar firmas desconocidas y empezar una sesión nueva. Hola carrito vacío.
La solución fue tan aburrida que casi no ocurrió: dejaron de tratar a los servidores de producción como mascotas. Pusieron la configuración bajo control de versiones, desplegaron el mismo wp-config.php entre nodos y añadieron una verificación de inicio que confirmaba que los hashes de salts coincidían. También fijaron despliegues de plugins a un único artefacto.
No salió nada «innovador». Pero la tasa de incidentes bajó. Las guardias se volvieron más tranquilas. Y el carrito dejó de comportarse como un pez dorado.
Broma corta #2: Si tus nodos web tienen salts diferentes, tu clúster no es “alta disponibilidad”. Es “elige tu propia aventura”, excepto que el final siempre son tickets de soporte.
Errores comunes: síntoma → causa raíz → solución
Esta es la parte donde dejas de adivinar.
1) Síntoma: Carrito se vacía inmediatamente al actualizar
Causa raíz: Cookie de sesión no enviada (desajuste de dominio/HTTPS) o sesión no escrita.
Solución: Forzar un nombre de host canónico, forzar HTTPS, verificar que las cookies incluyan path=/, y comprobar advertencias de PHP que impidan Set-Cookie. Validar presencia de wp_woocommerce_session_*.
2) Síntoma: Carrito se vacía solo en páginas cart/checkout
Causa raíz: Esas páginas están cacheadas (CDN/Varnish/FastCGI/plugin de caché).
Solución: Evitar la caché para /cart, /checkout, /my-account y endpoints AJAX de WooCommerce. Confirmar que el origen envíe no-store y que las cachés lo respeten.
3) Síntoma: Carrito se vacía “aleatoriamente” en un entorno multi-servidor
Causa raíz: Inconsistencia entre nodos (salts/config distintos), almacenamiento no compartido o balanceador que cambia sin consistencia de sesión compartida.
Solución: Haz la configuración idéntica en todos los nodos (salts, plugins, versiones WP). Asegura que el almacenamiento de sesiones de WooCommerce sea compartido y que las lecturas sean consistentes. Usa stickiness solo como mitigación temporal.
4) Síntoma: Carrito se vacía tras iniciar sesión
Causa raíz: Casos límites de migración de sesión más caché que varía según cookies de login pero no según cookies de WooCommerce, o desajuste de dominio de cookie.
Solución: Asegura bypass de caché cuando existan cookies de sesión de WooCommerce. Confirma host canónico antes del login. Prueba el flujo de inicio de sesión con y sin artículos en el carrito.
5) Síntoma: Mini-carrito aparece vacío, pero la página de carrito muestra artículos
Causa raíz: Endpoint de fragmentos de carrito cacheado o bloqueado; o una optimización JS rompe la actualización de fragmentos.
Solución: Excluir wc-ajax=get_refreshed_fragments de la caché y de las reglas del WAF. Verificar errores en la consola del navegador y las respuestas de red.
6) Síntoma: Carrito funciona y luego se vacía tras unos minutos
Causa raíz: Expiración/limpieza de sesiones demasiado agresiva, desajuste de hora del servidor o evicción de Redis afectando estado de soporte.
Solución: Validar timestamps de expiración de sesiones, comportamiento de limpieza por cron y sincronización NTP. Revisar evicted_keys en Redis.
7) Síntoma: Carrito se vacía solo en algunas geografías
Causa raíz: Reglas de caché en borde del CDN que difieren por región; o redirecciones geoespecíficas que cambian hostname/protocolo.
Solución: Estandariza reglas de redirección globalmente. Asegura que la clave de caché incluya cookies relevantes o bypass para páginas personalizadas en todas las POPs, no solo en la POP “principal”.
8) Síntoma: Carrito se vacía bajo carga
Causa raíz: Timeouts en peticiones add-to-cart, contención en la tabla de sesiones de la BD o saturación de PHP-FPM.
Solución: Ajusta PHP-FPM, optimiza la BD (índices, arreglar consultas lentas) y reduce la carga de plugins. Monitoriza timeouts y tasas de 5xx específicamente en endpoints AJAX de WooCommerce.
Listas de verificación / plan paso a paso
Fase 1: Reproducir y aislar (15–30 minutos)
- Reproducir en incógnito en escritorio y móvil. Anotar la página exacta donde el carrito desaparece.
- Probar host canónico: usar siempre el mismo hostname y HTTPS.
- Revisar cabeceras en
/carty/checkouten busca de aciertos de caché y control de caché incorrecto. - Comprobar cookies tras add-to-cart: confirmar que
wp_woocommerce_session_*se establece y devuelve.
Fase 2: Matar las cachés incorrectas (sin destruir el rendimiento)
- Desactivar caché de página para:
/cart//checkout//my-account//?wc-ajax=*
- Evitar la caché cuando existan cookies de WooCommerce:
woocommerce_items_in_cartwoocommerce_cart_hashwp_woocommerce_session_*
- Confirmar con curl que desaparecen
Agey cabeceras de acierto de caché en cart/checkout.
Fase 3: Hacer las sesiones fiables entre nodos
- Asegurar salts idénticos y configuración en todos los nodos.
- Revisar comportamiento del balanceador: si las peticiones son round-robin, confirmar que el almacenamiento de sesión es compartido y consistente.
- Eliminar lecturas a réplicas para sesiones de WooCommerce y consultas críticas de carrito si tienes retraso de replicación.
Fase 4: Hacer el almacenamiento aburrido (el mejor tipo de almacenamiento)
- Verificar salud de la BD: la tabla de sesiones existe, tiene índices y no se bloquea bajo carga.
- Verificar salud de Redis si se usa: sin tormentas de evicción, memoria adecuada y política sensata.
- Verificar espacio en disco y permisos de ficheros; eliminar fallos intermitentes de escritura.
Fase 5: Pruebas de regresión que debes conservar
- Añadir al carrito → actualizar página del carrito → sigue con artículos.
- Añadir al carrito → iniciar sesión → carrito preservado.
- Añadir al carrito → cambiar entre
wwwy sinwwwnunca debería ocurrir; verificar que no pase. - Añadir al carrito → página de checkout muestra artículos y totales; el mini-carrito coincide.
- Repetir con CDN activado y desactivado para asegurar que las reglas en el borde son correctas.
Preguntas frecuentes
1) ¿Por qué el carrito se vacía solo después de actualizar, no inmediatamente?
Porque add-to-cart puede tener éxito (cookies establecidas, sesión escrita), pero la actualización es servida por una capa de caché o un nodo backend distinto que no ve ese estado. La actualización es donde los errores de caché y enrutamiento se hacen visibles.
2) ¿Debería desactivar toda la caché para WooCommerce?
No. Cachea agresivamente páginas de producto/categoría, pero trata carrito/checkout/account como personalizados. Desactivar todo es dejar dinero sobre la mesa y castigar tus orígenes sin razón.
3) ¿Suele deberse a un plugin?
A menudo, sí—pero no es que “WooCommerce esté fallando”. Los culpables comunes son plugins de caché, plugins de seguridad que reescriben cabeceras y plugins de “optimización” que minifican/diferir scripts y rompen los fragmentos del carrito.
4) ¿Necesito sesiones pegajosas en el balanceador?
Las sesiones pegajosas pueden enmascarar problemas, pero no son la solución ideal. La mejor respuesta es almacenamiento de sesiones compartido y consistente y configuración idéntica entre nodos. Usa stickiness como mitigación corta durante un incidente.
5) ¿Puede Redis causar pérdida de carrito?
Indirectamente. Si almacenas estado crítico tipo sesión en Redis o dependes de helpers cacheados y Redis está expulsando claves por presión de memoria, el comportamiento se vuelve inconsistente. Arregla el dimensionamiento y la política de evicción, y asegúrate de que el estado crítico no sea solo “cache”.
6) ¿Por qué ocurre más en móvil o Safari?
Las reglas de cookies son más estrictas y la prevención de rastreo es más agresiva. Si tienes redirecciones entre dominios, protocolo mixto o ajustes raros de SameSite, los navegadores móviles te penalizarán primero.
7) ¿Cómo sé si el CDN está cacheando mi página de carrito?
Mira las cabeceras: Age, cabeceras de estado de caché del CDN y cualquier indicador de HIT. También compara cuerpos HTML entre dos clientes diferentes; si coinciden sospechosamente, estás cacheando contenido personalizado.
8) ¿Puede el rendimiento de la base de datos causar que el carrito “se vacíe”?
Sí. Si las escrituras de sesión agotan el tiempo o las lecturas son tan lentas que fallan, WooCommerce puede crear una sesión nueva. Bajo carga, esto parece “carrito que se vacía aleatoriamente”. Revisa timeouts de PHP-FPM y logs de consultas lentas en la BD.
9) Mi carrito se vacía solo tras iniciar sesión. ¿Cuál es la solución más rápida?
Primero, asegúrate de no cambiar hostname/protocolo durante el login. Segundo, evita la caché cuando existan cookies de sesión de WooCommerce. Tercero, confirma que las salts coinciden entre nodos para que las cookies de login se validen de forma consistente.
10) ¿Cuál es la causa raíz más común?
Cacheado inadecuado de páginas cart/checkout o no variar la caché por cookies de WooCommerce. Es la victoria de rendimiento más fácil de implementar y la forma más rápida de romper ingresos.
Conclusión: siguientes pasos que no te desperdiciarán el fin de semana
Arreglar “carrito vacío tras actualizar” va principalmente de disciplina con el estado. Empieza con el diagnóstico rápido: confirma si estás perdiendo cookies/sesiones o sirviendo HTML cacheado. Luego quita la caché de los pocos endpoints que deben ser dinámicos. Después de eso, haz el comportamiento multinodo aburrido: configuración idéntica, estado compartido y nada de sorpresas por retraso en réplicas.
Pasos prácticos siguientes:
- Ejecuta comprobaciones de cabeceras en
/carty/checkouty elimina aciertos de caché allí. - Verifica que las cookies de WooCommerce se establecen y devuelven en el host canónico HTTPS.
- Audita el comportamiento del balanceador de carga y la deriva de configuración entre nodos (especialmente salts).
- Valida escrituras en la tabla de sesiones de WooCommerce y asegura que las lecturas no vayan a réplicas con retraso.
- Revisa la evicción de Redis y los timeouts de PHP-FPM si el problema se correlaciona con la carga.
Haz esos cinco, y normalmente pasarás de “amnesia misteriosa del carrito” a un checkout estable. Que es el objetivo de gestionar una tienda.