Headless-витрина WooCommerce может быстро получать товары через API, но настоящая сложность начинается с корзины и оформления заказа. Если клиент не сохраняет идентификатор корзины, неправильно обновляет защитный токен или смешивает cookie-сессию с собственным состоянием, пользователь видит пустую корзину, старую сумму или ошибку уже на checkout.
WooCommerce Store API создан именно для клиентских сценариев каталога, корзины и оформления заказа. Ниже разберём рабочую архитектуру для SPA, Next.js и других отдельных фронтендов без попытки превращать публичный Store API в административный REST API.
Чем Store API отличается от WooCommerce REST API
Store API работает в пространстве /wp-json/wc/store/v1/ и предназначен для данных текущего покупателя: товаров, корзины, доставки и checkout. Он не предназначен для чтения чужих заказов, изменения настроек магазина или административной синхронизации.
Для CRM, складской системы и серверной работы с заказами нужен аутентифицированный WooCommerce REST API. Для покупательского интерфейса Store API обычно лучше соответствует задаче и не требует размещать consumer key и consumer secret во frontend bundle.
Главная задача: сохранить одну и ту же корзину
Обычный WooCommerce умеет связывать покупателя с корзиной через cookie-сессию. В headless-архитектуре frontend может жить на другом домене, поэтому полагаться только на cookies неудобно. Для этого WooCommerce поддерживает Cart Token.
Первый запрос можно сделать к GET /wp-json/wc/store/v1/cart. В заголовках ответа Store API возвращает Cart-Token. Клиент сохраняет его и передаёт в следующих запросах корзины и checkout:
GET /wp-json/wc/store/v1/cart
Cart-Token: <token>
Для браузерного приложения токен удобно хранить в контролируемом состоянии приложения и восстанавливать после перезагрузки. При этом не нужно превращать Cart-Token в пользовательский логин: это идентификатор конкретной корзины, а не административная авторизация.
Cart-Token или Nonce
WooCommerce также поддерживает Nonce Tokens. POST-запросы к cart и запросы checkout требуют корректного Nonce, если вместо него не используется Cart-Token. После успешного запроса сервер может вернуть обновлённый Nonce, который клиент должен принять для последующих операций.
Для отдельного headless-фронтенда Cart-Token часто упрощает транспорт сессии: документация WooCommerce прямо указывает, что при использовании Cart-Token отдельный Nonce не требуется. Внутри WordPress-интерфейса или собственной интеграции, где nonce уже естественно генерируется сервером, можно использовать nonce-сценарий.
Добавление товара в корзину
Для добавления позиции используется POST /wc/store/v1/cart/add-item. Передаются ID товара или вариации, количество и при необходимости выбранные атрибуты. Store API возвращает не только изменённую строку, а актуальное состояние всей корзины.
POST /wp-json/wc/store/v1/cart/add-item
Cart-Token: <token>
Content-Type: application/json
{
"id": 123,
"quantity": 2
}
На frontend лучше считать ответ сервера источником истины. Не увеличивайте итоговую сумму только локально и не предполагайте, что цена осталась прежней: WooCommerce может применить налог, скидку, ограничение количества или другую серверную логику.
Вариативные товары
Для вариации нужно передавать корректный variation ID и атрибуты в формате Store API. Ошибка, которую часто допускают в кастомной витрине, — хранить только родительский product ID и пытаться восстановить вариацию по тексту кнопки.
Frontend должен работать с реальными идентификаторами WooCommerce и значениями атрибутов. Это особенно важно для магазина, где от вариации зависят цена, остаток, вес или возможность доставки.
Изменение количества и удаление
После добавления позиции Store API возвращает ключ элемента корзины. Именно его используют операции изменения и удаления. Для изменения количества доступен /cart/update-item, для удаления — /cart/remove-item.
После каждой операции заменяйте локальную модель корзины ответом API. Такой подход уменьшает рассинхронизацию между React/Vue/Next.js состоянием и расчётами WooCommerce.
Адрес и доставка должны считаться на сервере
Стоимость доставки зависит от адреса, состава корзины, shipping zones и настроек методов. Через Store API можно обновить данные покупателя, получить доступные shipping rates и выбрать нужный тариф.
Не стоит переносить правила WooCommerce Shipping в JavaScript и дублировать их вручную. Frontend отвечает за интерфейс, а итоговые тарифы и доступность методов должен определять WooCommerce.
Checkout через Store API
Endpoint /wc/store/v1/checkout работает с текущей корзиной и данными оформления. Финальный POST принимает billing/shipping address, выбранный payment method и при необходимости payment data.
В актуальном Store API также есть PUT /checkout, позволяющий сохранять данные draft order до финального платежа. Это полезно для многошагового checkout, но frontend всё равно должен корректно обрабатывать изменившуюся корзину и ошибки сервера.
Зачем передавать expected_total
При финальном checkout WooCommerce поддерживает поле expected_total — сумму, которую покупатель подтвердил на frontend, в минимальных денежных единицах. Если сервер пересчитал другую сумму, запрос может вернуть HTTP 409 и обновлённую корзину.
Это полезная защита от ситуации, когда пользователь увидел одну цену, а между отображением и оплатой изменились доставка, скидка или содержимое корзины. Клиент должен показать новую сумму и запросить подтверждение, а не автоматически продолжать оплату со старым UI.
Не кэшируйте персональную корзину как каталог
Product endpoints можно кэшировать гораздо агрессивнее, чем cart и checkout. Ответ корзины относится к текущей сессии. CDN или reverse proxy не должен раздавать один персональный cart response разным посетителям.
Для cart/checkout безопаснее использовать no-store на клиентской стороне и отдельно проверять правила Cloudflare, Nginx или другого CDN. Каталог и статические данные можно оптимизировать независимо.
CORS для отдельного домена
Если frontend находится на другом origin, необходимо проверить CORS и доступность нужных response headers. WooCommerce отдельно улучшал поддержку Cart-Token для cross-origin запросов. При этом не нужно бездумно добавлять Access-Control-Allow-Origin: * ко всему WordPress.
Отдельно о preflight, Authorization и reverse proxy я писал в материале про CORS WordPress REST API.
Типовые ошибки headless-корзины
- Cart-Token получили, но не сохранили после первого запроса;
- на одной странице используется Cart-Token, а на другой создаётся новая cookie-сессия;
- frontend считает сумму самостоятельно и не заменяет состояние ответом Store API;
- вариативный товар отправляется как родительский ID;
- checkout кэшируется на CDN;
- HTTP 409 воспринимается как обычный сбой вместо сигнала обновить итог;
- секреты административного WooCommerce REST API помещаются в публичный JavaScript;
- ошибка CORS маскируется бесконечными повторными запросами.
Практическая архитектура
- Frontend получает каталог через Store API.
- При первом обращении к корзине получает Cart-Token.
- Сохраняет токен и отправляет его для всех cart/checkout операций.
- После каждой мутации принимает полный свежий cart response.
- Адрес и shipping rate рассчитываются WooCommerce.
- Перед оплатой frontend показывает серверный total.
- При необходимости отправляет
expected_totalи корректно обрабатывает 409. - Административные операции остаются на backend и не смешиваются со Store API.
Когда нужна кастомная разработка
Стандартных endpoint достаточно для обычной корзины, но нестандартные product add-ons, сложные комплекты, внешние скидки, собственная доставка и платёжные шлюзы требуют проверки совместимости со Store API. Иногда нужно расширять Store API через предусмотренные WooCommerce механизмы, а не создавать параллельную корзину.
Если headless WooCommerce теряет корзину, неправильно считает checkout или требует интеграции с отдельным frontend, в A.S Groups можно заказать диагностику и разработку Store API-интеграции. Сначала проверю фактический flow запросов, токены, CORS, кэш и платёжный сценарий, а затем предложу решение без дублирования логики WooCommerce.
Обсуждение
Вопросы и комментарии
Можно уточнить детали статьи или поделиться своим опытом. Первый комментарий проходит проверку.