Мало що так убиває конверсію, як кошик, що начебто не існує. Покупець додає два товари, оновлює сторінку — і, бац, порожній кошик. Вони не починають дебаг; вони йдуть. А ви дивитеся на панелі, які вперто кажуть, що сайт «здоровий», бо HTTP 200 — це не те саме, що «люди можуть платити вам гроші».
Ця помилка майже ніколи не означає, що «WooCommerce поламався». Часом проблема — у втраті стану через кеш, область cookie, зберігання сесій чи маршрутизацію між вузлами. Добра новина: це можна виправити. Погана — треба бути точним, бо «очистіть усі кеші» — це не стратегія; це визнання вини.
Швидкий план діагностики
Якщо робити в правильному порядку, ви знайдете вузьке місце швидко. Якщо в неправильному — проведете день, звинувачуючи WooCommerce, і ніч, звинувачуючи себе.
Спершу: підтвердіть, чи це втрата cookie/сесії, чи кешований HTML
- Відкрийте вікно інкогніто, додайте товар до кошика, оновіть сторінку кошика і сторінку оформлення замовлення.
- Перевірте заголовки відповіді на предмет попадань у кеш (CDN, Varnish, Nginx FastCGI cache).
- Перевірте, чи з’являються cookie після додавання у кошик:
woocommerce_cart_hash,woocommerce_items_in_cart,wp_woocommerce_session_*.
Рішення: якщо HTML кешується, потрібні виключення кешу й правильна поведінка «vary». Якщо cookie не зберігаються — потрібно виправити область cookie, HTTPS, SameSite, домен або збереження сесій.
Далі: перевірте маршрутизацію між вузлами та стан бекенда сесій
- Ви за балансувальником навантаження? Чи є стікінесс? Чи зберігаються сесії WooCommerce у спільному сховищі (БД/Redis) між вузлами?
- Використовуєте Redis як object cache? Він втрачає ключі? Чи maxmemory виконує евікшен?
- Чи зростає латентність бази даних або блокуються таблиці?
Рішення: якщо у вас кілька веб-вузлів і немає спільного зберігання сесій/об’єктів (або воно некоректне), кошик «рандомно» зникатиме залежно від того, на який вузол потрапить запит.
Третє: перевірте таблицю сесій WooCommerce і поведінку cron
- WooCommerce за замовчуванням зберігає дані сесій у базі даних у виділеній таблиці.
- Планувальники очистки і TTL мають значення. Неправильно налаштований cleanup може видаляти живі сесії.
Рішення: якщо сесії видаляються або взагалі не записуються, ви помітите, що кошик зникає відразу після оновлення або після короткої бездіяльності.
Цитата, щоб тримати команду в чесності (перефразована ідея): Eugene Rochal у колах операцій/надійності популяризував думку, що надійність народжується з «очевидного й спостережуваного стану», а не з надії.
Що фактично відбувається, коли кошик «зникає»
Кошик WooCommerce — не магія. Це стан, що будується з кількох інгредієнтів:
- Клієнтські cookie, які ідентифікують сесію й несуть підказки (наприклад, хеш кошика).
- Серверні дані сесії (часто в
wp_woocommerce_sessionsабо з іншим префіксом таблиці), ключовані ідентифікатором сесії. - HTML-рендеринг, який не повинен кешуватися неправильно, бо він персоналізований.
Коли ви додаєте товар, WooCommerce записує або оновлює дані сесії, встановлює cookie і потім рендерить кошик/міні-кошик. Симптом «кошик зникає при оновленні» зазвичай означає одне з наступного:
- Браузер не відсилає назад cookie сесії (неправильна область/флаги cookie).
- Сервер не може знайти дані сесії (не записані, очищені або збережені в іншому місці).
- Кеш повертає чужу версію сторінки (або версію «без кошика»), бо ігнорує cookie або параметри запиту.
- Наступний запит обробляє інший веб-вузол і він не ділиться станом коректно.
Є варіанти:
- Кошик зникає тільки на сторінках кошика/чекауту: правила кешування націлені на ці URL або плагін, що «оптимізує» ці шляхи.
- Кошик зникає після входу: міграція сесії між гостем і зареєстрованим користувачем, невідповідність домену cookie або кеш, що варіює по куці входу, але не по WooCommerce cookie.
- Кошик зникає тільки в Safari/iOS: суворіші правила cookie (SameSite, ITP), обмеження сторонніх cookie або дивні потоки редиректів.
Короткий жарт №1: Якщо ваш кеш віддає однаковий кошик усім, вітаємо — ви винайшли «комунальний шопінг». Це не те, за що люди платять.
Цікаві факти та контекст (чому це повторюється)
- WooCommerce давно відійшов від PHP-сесій для стану кошика; він покладається на власну систему сесій плюс cookie, бо масштабування PHP-сесій у мультивузлових середовищах — класична пастка.
- Кешування сторінок у WordPress стало мейнстрімом, бо PHP+MySQL на shared-хостингу були повільні. E‑commerce — перше навантаження, яке карає за рефлекс «кешувати все».
- Varnish прославив ідею «попадання в кеш — це король» в 2000-х. Для кошиків «hit rate» — це марність, якщо персоналізовані сторінки не виключено коректно.
- Браузери посилили правила cookie хвилями (за замовчуванням SameSite, запобігання трекінгу). Багато багів із кошиком — це насправді «ваші флаги cookie — з 2016 року».
- CDN почали агресивно кешувати HTML, коли edge compute став доступним. Це чудово для блогів і жахливо для чекауту, якщо ви не врахували cookie в ключі кешу.
- Redis став типовим інструментом продуктивності в екосистемі WordPress. Неправильні політики евікшену можуть видаляти об’єкти, які код мовчки вважає доступними.
- WooCommerce використовує «cart fragments» через AJAX, щоб міні-кошик оновлювався без повного оновлення сторінки. Якщо ці AJAX-ендпоїнти кешуються або блокуються, інтерфейс бреше.
- Багато «безпекових» плагінів переписують заголовки (особливо флаги cookie і cache-control). Половина з них нормальна; інша половина — хаос із налаштуванням.
- Балансувальники полегшили горизонтальне масштабування. Водночас вони зробили узгодженість стану вашою проблемою, отже кошики «рандомно» зникають якраз після появи другого веб-вузла.
Режими відмов: сесії, cookie, кеш і сховище
1) Cookie: домен, шлях, HTTPS, SameSite і пастка з редиректами
Якщо кошик зникає відразу після оновлення, перший підозрюваний — cookie сесії, що не повертається. Поширені причини:
- Змішаний HTTP/HTTPS: add-to-cart відбувається на HTTPS, потім редирект чи канонізація переводить користувача на HTTP і secure-cookie втрачається.
- Неправильний домен cookie:
example.comvswww.example.com. Один встановлює cookie, інший їх не відсилає. - Шлях cookie занадто вузький: cookie встановлено для
/shop, а кошик на/cart. - Проблеми SameSite: редиректи платіжного провайдера або вбудовані потоки можуть поводитися інакше, коли cookie марковані неправильно.
- Заголовки вже відправлені: PHP-попередження або вивід можуть перешкоджати надійному встановленню cookie. Так, той старий плагін досі може зіпсувати вам день.
2) Кеш сторінок: віддача застарілого HTML «порожній кошик»
Кешування сторінок класне — поки не починає шкодити. Сторінки WooCommerce треба вважати персоналізованими, коли користувач має сесію кошика. Типові помилки:
- Кешуються URL кошика й оформлення (CDN, Varnish, Nginx FastCGI cache, плагін-кеш).
- Кеш варіює по cookie входу WordPress, але не по WooCommerce cookie. Гості з кошиком отримують версію «без кошика».
- Кешований endpoint cart fragments (
?wc-ajax=get_refreshed_fragments), через що UI показує порожній міні-кошик, хоча стан на сервері існує. - «Оптимізація для мобільних» кешує окремо, але не враховує cookie у ключі кешу, розділяючи поведінку між пристроями.
3) Object cache: припущення про Redis/Memcached та евікшен
Object cache зазвичай не зберігає сам кошик, але зберігає речі, від яких залежить WooCommerce: дані клієнта, продукти, зони доставки, фрагменти, transient-значення і іноді допоміжні дані сесії. Проблеми:
- Евікшен у Redis при нестачі пам’яті: ключі зникають, поведінка стає непередбачуваною, і кошик «іноді» скидається.
- Непостійний object cache між вузлами: у кожного вузла свій локальний cache; поведінка залежить від того, на який вузол потрапив запит.
- Поганий drop-in (
object-cache.php), що некоректно підтримує групи або несумісний з вашою версією WooCommerce.
4) Зберігання сесій: проблеми таблиці в БД, cleanup і відставання реплікації
Таблиця сесій WooCommerce зазвичай у MySQL/MariaDB. Вона працює — поки не починає повільно відповідати, блокуватися або перебувати на репліці з відставанням. Режими відмов:
- Read/write split з відставанням репліки: add-to-cart пише на primary, оновлення читає з replica, яка ще не встигла синхронізуватися, і сесія ніби відсутня.
- Надто агресивний cleanup: сесії видаляють занадто рано через TTL або неправильну роботу запланованих завдань.
- Пошкодження таблиці або відсутні індекси: пошуки сесій сповільнюються; таймаути можуть змусити WooCommerce вважати, що сесії немає.
5) Балансувальники і мультивузловий WordPress: синдром «працює на одному вузлі»
Класика: додали другий веб-сервер і раптом кошики зникають. Це не примха WooCommerce. Це ви запустили stateful-додаток, наче він статичний сайт.
- Немає стікінессу і локальне сховище для даних, які мають бути спільними.
- Різні salts/ключі на вузлах, що ламає валідацію cookie і викликає відхилення сесій.
- Різні версії плагінів на вузлах (таке трапляється) — як результат, непослідовна поведінка cookie/сесій.
6) Сховище й файлові системи: сесії — не єдиний шлях запису
Хоча сесії WooCommerce за замовчуванням підкріплені БД, середовище все одно записує на диск: логи, файли кешу, іноді кеші плагінів. Повний диск або файлові системи лише для читання можуть створити симптоми «кошик зникає» опосередковано (наприклад, плагіни тихо падають, БД не може писати, PHP не може створити тимчасові файли).
Практичні завдання: команди, виводи та рішення (12+)
Ось завдання, які я справді запускаю у продакшні. Кожне має: команду, типовий вивід, що це означає, і яке рішення приймати.
Task 1: Confirm cache behavior on cart page (headers)
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
Що це означає: HTML кошика кешується публічно і віддається з кешу. Це пряма причина «порожній кошик після оновлення» для деяких або всіх користувачів.
Рішення: Вимкніть кешування для /cart, /checkout і /my-account на кожному шарі (плагін-кеш, реверс-проксі, CDN). Також забезпечте, щоб кеш варіювався за WooCommerce cookie для динамічних сторінок.
Task 2: Check if WooCommerce cookies are set after add-to-cart
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/
Що це означає: Cookie встановлюються з path=/ і secure. Це добре. Якщо ви цього не бачите, кошик не збережеться.
Рішення: Якщо cookie відсутні, перевірте PHP-попередження/вивід, конфігурацію доменів cookie та HTTPS-редиректи. Якщо cookie є, але не повертаються — у вас проблема з політикою браузера або невідповідністю доменів.
Task 3: Verify cookie domain mismatch via response cookies
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
Що це означає: Якщо користувачі потрапляють як на shop.example.com, так і на www.shop.example.com, ви, ймовірно, встановлюєте окремі cookie для кожного хоста. Користувачі «втратять» кошики під час редиректів або при навігації між хостами.
Рішення: Виберіть один канонічний хост, редиректуйте інший і зробіть так, щоб home/siteurl у WordPress відповідали одному хосту. Уникайте конфігурацій «іноді www».
Task 4: Detect FastCGI cache on Nginx for cart/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
Що це означає: Nginx віддає кешований HTML оформлення. Це може сплющувати кошики до «порожніх» або призводити до того, що один користувач бачить стан іншого (ще гірше).
Рішення: Виключіть ендпоїнти WooCommerce з FastCGI cache і забезпечте, щоб ключ кешу варіювався за cookie сесії WooCommerce там, де потрібно.
Task 5: Check WooCommerce session table exists and has data
cr0x@server:~$ mysql -e "SHOW TABLES LIKE '%woocommerce_sessions%';"
+--------------------------+
| Tables_in_wp (%sessions%)|
+--------------------------+
| wp_woocommerce_sessions |
+--------------------------+
Що це означає: Таблиця існує. Наступний крок — перевірити записи і поведінку терміну життя.
Рішення: Якщо таблиці немає, у вас зламана інсталяція/міграція або плагін змінив обробник сесій. Виправте це перед маніпуляціями з кешем.
Task 6: Confirm sessions are being written and not instantly expired
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 |
+----------------------------------+---------------+
Що це означає: Часові мітки expiry виглядають розумно (в майбутньому). Якщо ви бачите expiry у минулому або дуже маленьке вікно — щось занадто агресивно видаляє сесії.
Рішення: Якщо expiry неправильний, перегляньте налаштування сесій WooCommerce, cron і будь-які кастомні job-скрипти. Також перевірте зсув часу сервера.
Task 7: Check database read/write split (replica lag)
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
Що це означає: Репліка відстає на 18 секунд. Якщо читання сесій йде до репліки, оновлення відразу після додавання у кошик може повернути «немає сесії», тобто порожній кошик.
Рішення: Не читайте критичні для кошика дані з реплік. Прив’язуйте читання/запис сесій WooCommerce до primary або забезпечте read-your-writes консистентність.
Task 8: Verify Redis is evicting keys (object cache instability)
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
Що це означає: Redis працює близько до maxmemory і має високу фрагментацію. Якщо ввімкнено евікшен, ключі можуть випадати під тиском пам’яті, спричиняючи непослідовну поведінку.
Рішення: Збільште пам’ять Redis, налаштуйте політику евікшену, зменште слід кешу або перемістіть важкі transient-дані в інше місце. Не тримайте стан e-commerce поруч зі «зголоднілим» кешем.
Task 9: Confirm Redis eviction policy and eviction counters
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
Що це означає: evicted_keys ненульовий і зростає — Redis видаляє ключі, щоб звільнити місце. Якщо плагіни чи теми припускають, що кешовані об’єкти завжди існують, UX стає непослідовним.
Рішення: Зупиняти евікшен у продакшн-кешах доречно лише якщо ви можете допустити відмови записів; зазвичай кращий підхід — правильне розмірювання й уникнення зберігання критичного стану тільки в Redis.
Task 10: Check that all web nodes share the same WordPress salts
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... -
Що це означає: Хеші відрізняються. Це погано. Валідація cookie і поведінка, пов’язана з авторизацією/сесіями, може відрізнятися на кожному вузлі.
Рішення: Зробіть wp-config.php ідентичним на всіх вузлах (ідеально через конфігураційний менеджмент). За потреби перезапустіть PHP-FPM. Потім повторно протестуйте кошики.
Task 11: Check load balancer stickiness and backend switching
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
Що це означає: Запити чергуються між вузлами. Якщо сховище сесій не спільне або неконсистентне, кошики можуть зникати при оновленні залежно від того, який бекенд обслуговує запит.
Рішення: Або реалізуйте stickiness (тимчасова пластирка), або виправте спільний стан (правильне довгострокове рішення). Для WooCommerce спільна таблиця сесій у БД зазвичай працює, якщо читання/записи консистентні і латентність контрольована.
Task 12: Verify PHP-FPM is not dropping requests or timing out on session writes
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)
Що це означає: Ви насичуєте PHP-FPM воркери і маєте таймаути під час add-to-cart AJAX. Якщо запис не встигає, наступне оновлення може показувати порожній кошик.
Рішення: Збільшіть capacity: підніміть pm.max_children, якщо дозволяють CPU/RAM, оптимізуйте повільні запити і припиніть фонові плагіни, що забирають воркери.
Task 13: Check Nginx access log for cart fragment caching or anomalies
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"
Що це означає: Нормальний потік відбувається. Якщо ви бачите 301/302 петлі, 403 (WAF) або підозрілі заголовки кешування на цих ендпоїнтах, міні-кошик може брехати.
Рішення: Виключіть ці AJAX-ендпоїнти з кешу й переконайтесь, що WAF їх не блокує. Вони обов’язкові для адекватного UX.
Task 14: Validate disk space and read-only filesystem (the boring sabotage)
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
Що це означає: Місткість майже вичерпана. Браку тимчасового простору може зламати завантаження, плагіни кешу, обробку зображень і іноді операції, пов’язані з сесіями, залежно від стеку.
Рішення: Звільніть місце негайно. Потім налаштуйте моніторинг і нормальне ротацію логів. Не дозволяйте «no space left on device» маскуватися під баг WooCommerce.
Task 15: Check WooCommerce-specific no-cache headers (should exist on sensitive pages)
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
Що це означає: Ці заголовки здорові. Якщо ви бачите public або довгий max-age, ваш шар кешування може ігнорувати інструкції origin або переписувати заголовки.
Рішення: Зробіть так, щоб кешуючі шари поважали заголовки origin на сторінках кошика/чекауту, або встановіть правила обходу кешу за шляхом і cookie.
Три корпоративні міні-історії з фронту
Міні-історія 1: Іncидент через хибне припущення («репліки підходять для читань»)
У них був чистий діаграмний стек і хаотична реальність. Стек — WordPress + WooCommerce за балансувальником, база розділена на primary для записів і replica для читань. Це працювало для блогів і сторінок продуктів. Графіки виглядали чудово. Усі підбивали руки за «масштабування».
Потім кошик почав зникати. Не завжди. Досить часто, щоб розворушити доходи і створити тікети з тим самим тоном, що й скарги на багаж авіакомпанії. Он-кол інженер робив те, що роблять он-кол інженери: перезапускав PHP-FPM, чистив кеші і дивився логи, поки кава не стала способом виживання.
Корінь проблеми — хибне припущення: «читання сесій — це просто читання». WooCommerce записував дані сесії при add-to-cart на primary, а сторінка кошика читала з replica, оскільки запит виглядав як читання. При навантаженні з відставанням репліки запису не було видно одразу. Сайт поводився як з амнезією, але лише на кілька секунд після зміни.
Виправлення було дратівливо простим і політично непростим: перестали відправляти читання таблиці сесій WooCommerce на репліку. Вони ввели правило, щоб ці запити фіксувалися на primary. Конверсія відновилася миттєво. На наступному архітектурному рев’ю ніхто не хотів про це говорити — бо діаграма стала менше елегантною.
Урок: консистентність «читання-після-запису» важливіша за «чисте розділення» коли клієнти натискають «Place order».
Міні-історія 2: Оптимізація, що підвела («кампанія cache everything»)
Ініціатива продуктивності пройшла як невинний шторм. Було чітке доручення: підвищити cache hit rate. Хтось додав агресивні правила кешування на зворотньому проксі і налаштування CDN, щоб кешувати HTML динамічних сторінок з коротким TTL. Це зробило швидкими сторінки продуктів. Також це зробило швидкою сторінку кошика — швидкою в тому, щоб бути неправильною.
Клієнти скаржилися, що кошики зникають при оновленні. Інші бачили чужий лічильник у заголовку. Той другий симптом перетворює баг на засідання з безпеки. Корінь: ключ кешу не варіювався по WooCommerce cookie. CDN бачив /cart/ як однакову сторінку для всіх.
Команда намагалася «очищати все» щогодини. Зменшували TTL до 10 секунд. Додавали query string. Це все було лікуванням симптомів кеш-поживи, а не проблеми дизайну. Вони кешували персоналізований HTML без ключа персоналізації.
Справжнє виправлення було непомітним: обходити кеш для сторінок кошика/чекауту/аккаунта і обходити кеш, коли є WooCommerce cookie. Для всього іншого кешувати як звичайно. Hit rate впав. Доходи зросли. Який метрик ви хочете пояснити фінансовому директору?
Міні-історія 3: Нудна, але правильна практика, що врятувала день (консистентність конфігурації)
Ще одна організація мала три веб-вузли і звичку робити «гарячі фікси». Інженер заходив по SSH на вузол, редагував wp-config.php і вважав задачу виконаною. Наступний інженер робив те саме на іншому вузлі. З часом вузли дрейфували як континенти: різні salts, різні файли плагінів, трохи відмінні PHP INI.
Втрата кошика здавалась «рандомною». Це не було випадковістю; це була детермінована хаотичність. Користувач додавав товар, оновлював сторінку, потрапляв на інший бекенд — і cookie сесії не проходили валідацію. Система робила те, що їй наказали: відхиляла невідомі підписи й починала нову сесію. Вітаємо: порожній кошик.
Виправлення було нудне: вони перестали ставитися до продакшн-серверів як до домашніх улюбленців. Поставили конфіг під контроль версій, деплоїли однаковий wp-config.php на всі вузли й додали стартову перевірку, що хеші salts збігаються. Також закріпили деплоя плагінів одним артефактом.
Нічого «інноваційного» не сталося. Але кількість інцидентів впала. Он-кол став тихішим. І кошик перестав грати роль золотої рибки пам’яті.
Короткий жарт №2: Якщо у ваших веб-вузлів різні salts, ваш кластер не «high availability». Це «обери свою пригоду», лише кінець завжди — тікети у підтримці.
Поширені помилки: симптом → корінь → виправлення
Тут ви перестаєте гадати.
1) Симптом: Кошик зникає відразу при оновленні
Корінь: Cookie сесії не відсилається назад (невідповідність домену/HTTPS) або сесія не записується.
Виправлення: Примусово використовуйте один канонічний хост, включіть HTTPS, перевірте, що cookie мають path=/, і перевірте PHP-попередження, які заважають Set-Cookie. Підтвердіть наявність wp_woocommerce_session_*.
2) Симптом: Кошик зникає тільки на сторінках кошика/чекауту
Корінь: Ці сторінки кешуються (CDN/Varnish/FastCGI/плагін).
Виправлення: Обходьте кеш для /cart, /checkout, /my-account та ендпоїнтів AJAX WooCommerce. Переконайтесь, що origin відсилає no-store і шари кешу це поважають.
3) Симптом: Кошик «рандомно» зникає в мультисерверній конфігурації
Корінь: Несумісність вузлів (різні salts/конфіг), не-спільне сховище або балансувальник перемикає бекенди без консистентності сесій.
Виправлення: Узгодьте конфіг на вузлах (salts, плагіни, версії WP). Забезпечте спільне зберігання сесій WooCommerce і консистентні читання. Використовуйте стікінесс лише тимчасово.
4) Симптом: Кошик зникає після входу
Корінь: Крайнє число сценаріїв міграції сесії плюс кеш, що варіює по cookie входу, але не по WooCommerce cookie, або невідповідність доменів cookie.
Виправлення: Забезпечте обход кешу, коли є WooCommerce cookie. Переконайтеся в канонічності хоста до входу. Протестуйте потік входу з товарами в кошику і без них.
5) Симптом: Міні-кошик показує порожнє, а сторінка кошика — з товарами
Корінь: Ендпоїнт cart fragments кешується або блокується; або оптимізація JS ламає оновлення фрагментів.
Виправлення: Виключіть wc-ajax=get_refreshed_fragments з кешу і правил WAF. Перевірте консоль браузера на помилки і мережеві відповіді.
6) Симптом: Кошик працює, але зникає через кілька хвилин
Корінь: Закінчення терміну життя сесії/забірку cleanup занадто агресивний, зсув часу сервера або евікшен Redis впливає на допоміжний стан.
Виправлення: Перевірте expiry timestamps сесій, поведінку cron і синхронізацію NTP. Перевірте evicted_keys у Redis.
7) Симптом: Кошик зникає тільки для деяких регіонів
Корінь: Правила кешування CDN відрізняються по регіонах; або гео-редиректи змінюють хост/протокол.
Виправлення: Уніфікуйте правила редиректів глобально. Забезпечте ключ кешу, що включає релевантні cookie, або обходьте кеш для персоналізованих сторінок у всіх POPs.
8) Симптом: Кошик зникає під навантаженням
Корінь: Таймаути на add-to-cart запитах, контенція в БД на таблиці сесій або насичення PHP-FPM.
Виправлення: Налаштуйте PHP-FPM, оптимізуйте БД (індекси, повільні запити) і зменшіть наклад плагінів. Моніторте таймаути і 5xx по AJAX-ендпоїнтах WooCommerce.
Чеклісти / покроковий план
Фаза 1: Відтворення і ізоляція (15–30 хвилин)
- Відтворіть у інкогніто на десктопі й мобільному. Занотуйте точну сторінку, де кошик зникає.
- Перевірте канонічний хост: завжди використовуйте один і той же hostname і HTTPS.
- Перевірте заголовки на
/cartі/checkoutщодо попадань у кеш і неправильного cache-control. - Перевірте cookie після add-to-cart: підтвердіть наявність
wp_woocommerce_session_*і повернення її в запитах.
Фаза 2: Вбити неправильні кеші (без шкоди для продуктивності)
- Вимкніть кешування сторінок для:
/cart//checkout//my-account//?wc-ajax=*
- Обходьте кеш, коли є WooCommerce cookie:
woocommerce_items_in_cartwoocommerce_cart_hashwp_woocommerce_session_*
- Підтвердіть за допомогою curl, що заголовки
Ageі маркери попадання в кеш зникли на cart/checkout.
Фаза 3: Зробіть сесії надійними між вузлами
- Забезпечте ідентичні salts і конфіг на всіх вузлах.
- Перевірте поведінку балансувальника: якщо запити round-robin, переконайтесь, що сховище сесій спільне і консистентне.
- Приберіть читання з реплік для сесій WooCommerce і критичних для кошика запитів, якщо є відставання реплікації.
Фаза 4: Зробіть сховище нудним (найкращий тип сховища)
- Перевірте здоров’я БД: таблиця сесій існує, індексована і не блокується під навантаженням.
- Перевірте здоров’я Redis, якщо використовується: немає евікшен-штормів, адекватна пам’ять, адекватна політика.
- Перевірте місце на диску і права файлів; усуньте переривчасті помилки запису.
Фаза 5: Регресійні тести, які варто зберегти
- Add-to-cart → оновити сторінку кошика → товари залишились.
- Add-to-cart → вхід → кошик збережений.
- Add-to-cart → перемикання між
wwwі безwwwне повинно відбуватися; перевірте це. - Add-to-cart → сторінка оформлення замовлення показує товари і підсумки; міні-кошик відповідає.
- Повторіть з CDN увімкненим і вимкненим, щоб переконатися, що правила на краю правильні.
Поширені питання (FAQ)
1) Чому кошик зникає тільки після оновлення, а не відразу?
Бо add-to-cart може пройти успішно (cookie встановлено, сесія записана), але оновлення обслуговується іншим шаром кешу або бекенд-вузлом, який не бачить цього стану. Оновлення — це момент, де помилки кешу і маршрутизації стають помітними.
2) Чи варто просто вимкнути все кешування для WooCommerce?
Ні. Кешуйте агресивно сторінки продуктів/категорій, але трактуйте cart/checkout/account як персоналізовані. Повне відключення — це гроші на столі і непотрібне навантаження на origin.
3) Чи зазвичай це викликано плагіном?
Часто так — але не тому, що «WooCommerce багатий». Зазвичай винуватцями є плагіни кешу, безпеки, що переписують заголовки, і «оптимізатори», що мініфікують/відкладають скрипти і ламають cart fragments.
4) Чи потрібні стікінесс сесій на балансувальнику?
Stickiness може приховати проблему, але це не ідеальне рішення. Краще — спільне і консистентне зберігання сесій і ідентична конфігурація на вузлах. Використовуйте stickiness тимчасово під час інциденту.
5) Чи може Redis спричиняти втрату кошика?
Опосередковано — так. Якщо критичний стан або допоміжні дані лежать лише в Redis і він евіктує ключі під тиском пам’яті, поведінка стане непослідовною. Вирішіть розмір Redis, політику евікшену і переконайтесь, що критичний стан не зберігається тільки в кеші.
6) Чому це трапляється частіше на мобільних або Safari?
Правила cookie там стрімкіші й захист від трекінгу агресивніший. Якщо є крос-доменні редиректи, змішаний протокол або дивні налаштування SameSite, мобільні браузери будуть карати вас першими.
7) Як дізнатися, чи CDN кешує мою сторінку кошика?
Подивіться на заголовки: Age, статус кешу CDN і будь-які індикатори HIT. Також порівняйте тіла HTML між двома різними клієнтами; якщо вони підозріло однакові, ви кешуєте персоналізований контент.
8) Чи може продуктивність БД спричинити «порожній» кошик?
Так. Якщо запис сесії таймаутиться або читання достатньо повільне, WooCommerce може перейти на нову сесію. Під навантаженням це виглядає як «рандомна втрата кошика». Перевірте таймаути PHP-FPM і логи повільних запитів БД.
9) Кошик зникає тільки після входу. Яке найшвидше виправлення?
Спочатку переконайтесь, що під час входу не відбувається зміна хоста/протоколу. По-друге, обходьте кеш, коли є WooCommerce cookie. По-третє, підтвердіть, що salts збігаються на всіх вузлах, щоб cookies входу валідовались послідовно.
10) Яка найпоширеніша коренева причина?
Неправильне кешування сторінок кошика/чекауту або відсутність варіювання кешу по WooCommerce cookie. Це найпростіший спосіб зламати дохід і найшвидше виправлення.
Висновок: наступні кроки, що не зіпсують ваш уїкенд
Виправлення «кошик зникає після оновлення» — здебільшого дисципліна управління станом. Почніть зі швидкої діагностики: підтвердіть, чи втрачаєте ви cookie/сесії, чи віддаєте кешований HTML. Потім видаліть кешування з тих кількох ендпоїнтів, що мають бути динамічними. Далі зробіть поведінку мультивузловості нудною: тотожна конфігурація, спільний стан і без сюрпризів від реплік.
Практичні наступні кроки:
- Запустіть перевірки заголовків на
/cartі/checkoutі усуньте попадання в кеш там. - Підтвердіть, що WooCommerce cookie встановлюються і повертаються на канонічному HTTPS-хості.
- Аудит поведінки балансувальника і дрейфу конфігурації між вузлами (особливо salts).
- Перевірте записи у таблиці сесій WooCommerce і забезпечте, щоб читання сесій не йшло на відстаючі репліки.
- Перевірте евікшен Redis і таймаути PHP-FPM, якщо проблема корелює з навантаженням.
Зробіть ці п’ять кроків — і ви, як правило, перейдете від «загадкової амнезії кошика» до стабільного чекауту. Адже саме для цього ви і тримаєте магазин.