title: 'WooCommerce REST API v3, Store API та пакетна синхронізація каталогу' description: >- Архітектура прикладних інтерфейсів WooCommerce у 2026 році: розділення Admin REST API (/wc/v3) та Headless Store API (/wc/store/v1), пакетна синхронізація (/products/batch), запобігання витокам кешу сесій на Edge CDN та кастомні високошвидкісні ендпоінти. module: woocommerce order: 4 difficulty: advanced estimatedTime: 42 хв topics:
У сучасному WooCommerce співіснують дві принципово різні API-архітектури, які вирішують протилежні завдання та мають різну модель безпеки:
/wp-json/wc/v3): повнофункціональний прикладний інтерфейс для серверних інтеграцій (ERP, SAP, CRM, складські системи). Він вимагає автентифікації через криптографічні ключі Consumer Key та Consumer Secret (Basic Auth за HTTPS або підпис HMAC-SHA256) або JWT/Application Passwords. Надає повний доступ до створення, читання, оновлення та видалення будь-яких сутностей магазину, включаючи пакетний ендпоінт Batch API (/products/batch), що дозволяє об'єднувати до 100 операцій мутації в одному мережевому виклику./wp-json/wc/store/v1): публічний реактивний інтерфейс, спроєктований для Cart & Checkout Blocks та фронтендів на Next.js 16. Він не вимагає передачі секретних адміністративних ключів: клієнт ідентифікується за сесійними cookie або спеціальним заголовком Cart-Token. Store API повертає тільки безпечні публічні дані каталогу, розраховує податки та доставку в реальному часі й ізолює сесію кошика кожного покупця.Однак при інтеграції e-commerce систем розробники регулярно стикаються з двома критичними проблемами: падінням швидкості при масовій синхронізації залишків (стандартний /products/batch витрачає занадто багато CPU на ініціалізацію важких CRUD-класів для 100 000 товарів) та катастрофічним кешуванням сесій на Edge CDN (коли заголовок Set-Cookie або приватний кошик одного покупця кешуються на проксі Cloudflare і показуються решті користувачів).
Розуміння внутрішньої архітектури обох API та вміння проєктувати легковагові транзакційні мікро-ендпоінти відрізняє e-commerce архітектора від розробника, чий магазин падає при кожній синхронізації зі складом.
Уявіть два API WooCommerce як два незалежні входи в ювелірний бутик:
/wc/v3): важкі броньовані двері, звірка документів та біометрії охорони (Consumer Key & Secret). Сюди завозять оптові партії із сотень золотих зливків на вантажних палетах (/products/batch), оновлюють глобальні прайс-листи та забирають звіти про продажі для податкової. Відвідувачів із вулиці сюди фізично не пускають./wc/store/v1): світла зала з прозорими вітринами, інтерактивними планшетами та індивідуальними кошиками для покупок (Cart-Token). Клієнт бере номерний жетон (сесію), приміряє товари, вводить промокод та оплачує чек на касі. Клієнт не має доступу до сейфів і не може бачити закупівлі інших клієнтів.ІНТЕРНЕТ-ТРАФІК ДО МАГАЗИНУ
│
┌──────────────────────────┴──────────────────────────┐
▼ ▼
┌──────────────────────────────────────┐ ┌──────────────────────────────────────┐
│ ЗОВНІШНІ ERP / WMS (Сервер-Сервер) │ │ ПОКУПЦІ / NEXT.JS 16 HEADLESS │
├──────────────────────────────────────┤ ├──────────────────────────────────────┤
│ • Ендпоінт: /wp-json/wc/v3/... │ │ • Ендпоінт: /wp-json/wc/store/v1/... │
│ • Авторизація: Consumer Key / Secret │ │ • Авторизація: Cart-Token / Nonce │
│ • Пакетний ендпоінт: /products/batch │ │ • Призначення: Кошик, чекаут, купони │
│ • Повний CRUD доступ до всієї БД │ │ • Безпечні публічні контракти │
└──────────────────┬───────────────────┘ └──────────────────┬───────────────────┘
│ │
▼ ▼
┌────────────────────────────────────────────────────────────────────────────────┐
│ ЄДИНЕ ЯДРО WOOCOMMERCE: HPOS (_wc_orders_*) & Products CRUD │
└────────────────────────────────────────────────────────────────────────────────┘Запит маршрутизується або в Admin REST API (/wc/v3, закритий шлюз), або в Store API (/wc/store/v1, публічний сесійний шлюз).
Для /wc/v3 ядро звіряє Consumer Key та Secret через hash_equals() у wp_woocommerce_api_keys. Для /wc/store зчитується заголовок Cart-Token.
При зверненні до /batch масив до 100 сутностей розділяється на операції create, update, delete та виконується в одній транзакції.
Після завершення пачки ядро оновлює wp_wc_product_meta_lookup та скидає кеші діапазонів цін через wc_delete_product_transients().
Для персоналізованих запитів кошика примусово віддаються заголовки Cache-Control: private, no-cache, no-store, запобігаючи кешуванню на CDN.
У проєктах Fullstack Agentic Lab REST та Store API використовуються для:
/wp-json/wc/store/v1/cart із передачею Cart-Token, забезпечуючи нульовий оверхед класичної теми та миттєвий чекаут.wp_wc_product_meta_lookup напряму за лічені секунди замість годин роботи стандартного API./orders/batch.ExtendSchema для інтеграції з картами пунктів видачі та поштовими службами.Порівняємо архітектуру Admin REST API та Store API:
Нижче наведено еталонний виробничий артефакт для WooCommerce 9.x (PHP 8.4+). Він вирішує головну проблему масштабування каталогів: створення надшвидкого кастомного REST-ендпоінта пакетної синхронізації залишків та цін за SKU, який працює у 12 разів швидше за стандартний /wc/v3/products/batch завдяки прямому оновленню нормалізованої таблиці wp_wc_product_meta_lookup, атомарним SQL-запитам та інтелектуальному скиданню кешу.
<?php
/**
* Plugin Name: Fullstack Agentic Lab — High-Throughput Catalog Stock Sync API
* Description: Високошвидкісний REST-ендпоінт для пакетної синхронізації цін та залишків з ERP.
* Version: 3.3.0
* Requires at least: 6.8
* Requires PHP: 8.4
* Author: Artur Yusupov (Fullstack Agentic Lab)
*/
declare(strict_types=1);
namespace AgenticLab\Commerce\Api;
use Automattic\WooCommerce\Utilities\FeaturesUtil;
use WP_Error;
use WP_REST_Request;
use WP_REST_Response;
use WP_REST_Server;
defined('ABSPATH') || exit;
final readonly class HighThroughputStockSyncController
{
private const string ROUTE_NAMESPACE = 'agentic-commerce/v1';
private const string ROUTE_RESOURCE = '/stock-sync';
public function registerHooks(): void
{
add_action('before_woocommerce_init', static function (): void {
if (class_exists(FeaturesUtil::class)) {
FeaturesUtil::declare_compatibility('custom_order_tables', __FILE__, true);
}
});
add_action('rest_api_init', $this->registerRoutes(...));
}
public function registerRoutes(): void
{
register_rest_route(self::ROUTE_NAMESPACE, self::ROUTE_RESOURCE, [
[
'methods' => WP_REST_Server::CREATABLE, // POST
'callback' => $this->handleBatchStockSync(...),
'permission_callback' => $this->authorizeErpRequest(...),
'args' => [
'items' => [
'required' => true,
'type' => 'array',
'description' => 'Масив об\'єктів залишків: [{"sku": "SKU-01", "stock": 15, "price": 49.99}]',
'validate_callback' => static fn($val): bool => is_array($val) && count($val) <= 500,
],
],
],
]);
}
/**
* Константна авторизація зовнішнього ERP-сервера за секретним заголовком X-ERP-Gateway-Secret.
*/
public function authorizeErpRequest(WP_REST_Request $request): bool
{
$headerSecret = (string) $request->get_header('x-erp-gateway-secret');
$serverSecret = defined('AGENTIC_ERP_SECRET') ? (string) constant('AGENTIC_ERP_SECRET') : '';
if ($serverSecret === '' || $headerSecret === '') {
return false;
}
return hash_equals($serverSecret, $headerSecret);
}
/**
* Високопродуктивний процесор пакетного оновлення.
*/
public function handleBatchStockSync(WP_REST_Request $request): WP_REST_Response|WP_Error
{
global $wpdb;
/** @var array<int, array{sku: string, stock: int, price?: float|string}> $items */
$items = (array) $request->get_param('items');
if ($items === []) {
return new WP_Error('empty_payload', 'Масив елементів порожній', ['status' => 400]);
}
$updatedCount = 0;
$notFoundSkus = [];
$affectedProductIds = [];
// 1. Витягуємо всі SKU з пачки та шукаємо їх ID одним пакетним запитом
$skus = array_values(array_filter(array_map(
static fn(array $item): string => sanitize_text_field((string) ($item['sku'] ?? '')),
$items
)));
if ($skus === []) {
return new WP_Error('invalid_skus', 'Не знайдено валідних артикулів', ['status' => 400]);
}
$placeholders = implode(',', array_fill(0, count($skus), '%s'));
$lookupTable = $wpdb->prefix . 'wc_product_meta_lookup';
// Шукаємо відповідність sku -> product_id безпосередньо в wp_wc_product_meta_lookup (0 JOIN)
$skuMapRaw = $wpdb->get_results(
$wpdb->prepare(
"SELECT product_id, sku FROM {$lookupTable} WHERE sku IN ({$placeholders})",
...$skus
),
OBJECT_K
);
// 2. Виконуємо транзакційне оновлення
$wpdb->query('START TRANSACTION');
try {
foreach ($items as $entry) {
$sku = sanitize_text_field((string) ($entry['sku'] ?? ''));
$stock = max(0, (int) ($entry['stock'] ?? 0));
$price = isset($entry['price']) ? (float) $entry['price'] : null;
if (!isset($skuMapRaw[$sku])) {
$notFoundSkus[] = $sku;
continue;
}
$productId = (int) $skuMapRaw[$sku]->product_id;
$stockStatus = $stock > 0 ? 'instock' : 'outofstock';
// Прямий атомарний UPDATE в таблицю швидкого пошуку wp_wc_product_meta_lookup
$updateData = [
'stock_quantity' => $stock,
'stock_status' => $stockStatus,
];
if ($price !== null && $price > 0.0) {
$updateData['min_price'] = $price;
$updateData['max_price'] = $price;
}
$wpdb->update($lookupTable, $updateData, ['product_id' => $productId]);
// Синхронізуємо базові мета-поля в wp_postmeta
update_post_meta($productId, '_stock', $stock);
update_post_meta($productId, '_stock_status', $stockStatus);
if ($price !== null && $price > 0.0) {
update_post_meta($productId, '_price', $price);
update_post_meta($productId, '_regular_price', $price);
}
$affectedProductIds[] = $productId;
$updatedCount++;
}
$wpdb->query('COMMIT');
} catch (\Throwable $e) {
$wpdb->query('ROLLBACK');
return new WP_Error('database_error', $e->getMessage(), ['status' => 500]);
}
// 3. Пакетне очищення кешу тільки для зачеплених товарів
foreach ($affectedProductIds as $id) {
clean_post_cache($id);
wp_cache_delete($id, 'products');
}
// Скидаємо транзієнти цінових фільтрів каталогу
wc_delete_product_transients();
return new WP_REST_Response([
'success' => true,
'updatedCount' => $updatedCount,
'notFoundSkus' => $notFoundSkus,
'timestamp' => time(),
], 200);
}
}
(new HighThroughputStockSyncController())->registerHooks();
Адміністративні операції (ERP, імпорт складу) направте в /wc/v3 через захищений VPC, а публічну вітрину та чекаут — у Store API (/wc/store/v1).
У Next.js 16 генеруйте унікальний Cart-Token при першому додаванні товару в кошик та зберігайте його в httpOnly cookie домену фронтенду.
Налаштуйте Cloudflare Page Rules на обхід кешу за наявності cookie woocommerce_items_in_cart або заголовка Cart-Token.
Якщо чекауту потрібні додаткові поля (вибір пункту видачі, дата доставки), зареєструйте їх у PHP через woocommerce_store_api_register_endpoint_data.