title: >- Архітектура WooCommerce 9.x: High-Performance Order Storage (HPOS), Data Stores та Cart/Checkout Blocks description: >- Глибокий розбір архітектури сучасного WooCommerce у WordPress 7.0+ (PHP 8.4+): нормалізоване сховище HPOS (таблиці wc_orders*), декларація сумісності FeaturesUtil, абстракція WC_Data_Store, Cart/Checkout Blocks на базі Interactivity API та ізоляція сесій. module: woocommerce order: 1 difficulty: advanced estimatedTime: 40 хв topics:
Історично архітектура WooCommerce будувалася на антипатерні: замовлення інтернет-магазину реєструвалися як звичайний Custom Post Type (post_type = 'shop_order'), а кожний атрибут транзакції (адреса доставки, телефон, статус оплати, валюта, податки) записувався окремим рядком у загальну таблицю wp_postmeta. У великому магазині на 100 000 замовлень таблиця wp_postmeta миттєво розросталася до десятків мільйонів рядків. Будь-який пошук замовлення за номером телефону чи вибірка неоплачених рахунків вимагали серії з 6–8 важких SQL JOIN-ів по неіндексованих текстових колонках meta_key/meta_value, спричиняючи взаємні блокування таблиць (Table Locks) і фатальне падіння бази даних під час сезонних розпродажів (Black Friday).
У сучасному стандарті WooCommerce 9.x+ (WordPress 7.0+, PHP 8.4+) обов'язковим фундаментом є High-Performance Order Storage (HPOS) — виділена реляційна схема даних із чотирьох нормалізованих таблиць із B-Tree індексами:
wp_wc_orders: ядро замовлення (ID, статус, валюта, загальна сума, ID покупця, дати створення та оплати).wp_wc_order_addresses: нормалізовані адреси доставки (shipping) та виставлення рахунку (billing) з прямими індексами за email, телефоном та країною.wp_wc_order_operational_data: технічні метадані платіжних шлюзів, ID транзакцій, дати фіскалізації та експорту.wp_wc_orders_meta: ізольована таблиця для кастомних метаполів сторонніх плагінів, позбавлена сміття інших типів записів.Уся робота з даними інкапсульована за патерном Data Store (WC_Data_Store). Розробники оперують типізованими об'єктами WC_Order та WC_Order_Query, а пряме звернення до get_post_meta() або WP_Query для замовлень на HPOS є критичним дефектом, що призводить до втрати даних та помилок.
Уявіть архітектуру WooCommerce до і після HPOS як еволюцію складського обліку в гіпермаркеті:
У старій моделі (EAV / wp_postmeta) кожен надрукований касовий чек розрізали ножицями на 40 окремих паперових смужок (одна смужка — прізвище, друга — телефон, третя — артикул) і скидали в один гігантський ящик посеред складу разом із чернетками статей блогу та коментарями. Щоб знайти чек клієнта за номером телефону, бухгалтеру доводилося перебирати 20 мільйонів папірців вручну.
В архітектурі HPOS замовлення потрапляють в електронну картотеку з чотирма броньованими секціями. У касира є чіткі каталожні індекси за прізвищем, номером телефону та датою. Пошук потрібної транзакції серед мільйона замовлень відбувається за первинним B-Tree індексом за < 2ms, не зачіпаючи контентну базу даних WordPress.
┌────────────────────────────────────────────────────────────────────────┐
│ ПРИКЛАДНИЙ ШАР (PHP 8.4+ / WC_Order / WC_Order_Query) │
└───────────────────────────────────┬────────────────────────────────────┘
│ Виклик WC_Data_Store::load('order')
▼
┌────────────────────────────────────────────────────────────────────────┐
│ ШАР СУМІСНОСТІ ТА ДИСПЕТЧЕРИЗАЦІЇ: FeaturesUtil::declare_compat... │
└───────────────────┬────────────────────────────────┬───────────────────┘
│ │
[HPOS АКТИВОВАНО: 99% магазинів] [CPT LEGACY: Застаріло]
▼ ▼
┌──────────────────────────────────────┐ ┌──────────────────────────────┐
│ ВИДІЛЕНІ HPOS-ТАБЛИЦІ (B-Tree Idx) │ │ ТАБЛИЦІ EAV MONOLITH (Вузьке)│
├──────────────────────────────────────┤ ├──────────────────────────────┤
│ • wp_wc_orders │ │ • wp_posts (post_type) │
│ • wp_wc_order_addresses (phone/email)│ │ • wp_postmeta (мільйони рядків│
│ • wp_wc_order_operational_data │ │ без складених індексів) │
│ • wp_wc_orders_meta │ └──────────────────────────────┘
└──────────────────────────────────────┘Плагін декларує підтримку HPOS через FeaturesUtil::declare_compatibility('custom_order_tables'). Без цього адмін-панель блокує перемикання на виділені таблиці.
При виклику wc_get_order($id) ядро завантажує активний адаптер сховища OrdersTableDataStore, який виконує швидкий SELECT зі складеними B-Tree індексами.
Дані адреси клієнта автоматично записуються у wp_wc_order_addresses, виключаючи роздування мета-таблиць і забезпечуючи миттєвий пошук за телефоном/email.
Пошук замовлень транслюється класом WC_Order_Query у прямий SQL-запит до таблиць HPOS без використання високовитратного ядра WP_Query.
Замовлення оформлюється через нові Cart/Checkout Blocks на базі Interactivity API та Store API (/wc/store/v1) з автоматичною валідацією SlotFill-полів.
В інженерних проєктах Fullstack Agentic Lab архітектура HPOS та Store API є обов'язковим стандартом для:
< 25ms, запобігання деградації бази даних при одночасних транзакціях.FeaturesUtil./wp-json/wc/store/v1) для миттєвої синхронізації кошика, застосування купонів та нативного чекауту без оверхеду класичної адмінки.WC_Order_Query завдяки прямим індексам по колонках date_created_gmt та status.Порівняємо дві архітектурні епохи збереження замовлень у WooCommerce:
Нижче наведено еталонний виробничий артефакт для WooCommerce 9.x (WordPress 7.0+, PHP 8.4+). Він демонструє:
FeaturesUtil::declare_compatibility() на хуку before_woocommerce_init.WC_Order_Query з константним часом доступу.$order->update_meta_data().<?php
/**
* Plugin Name: Fullstack Agentic Lab — HPOS Enterprise Order Gateway
* Description: Високопродуктивна робота із замовленнями через виділені таблиці HPOS та WC_Order_Query.
* Version: 3.0.0
* Requires at least: 6.8
* Requires PHP: 8.4
* Author: Artur Yusupov (Fullstack Agentic Lab)
*/
declare(strict_types=1);
namespace AgenticLab\Commerce;
use Automattic\WooCommerce\Utilities\FeaturesUtil;
use WC_Order;
use WC_Order_Query;
defined('ABSPATH') || exit;
final readonly class HposEnterpriseBootstrap
{
public function registerHooks(): void
{
// 1. КРИТИЧНО ВАЖЛИВО: Декларація сумісності з HPOS ДО ініціалізації WooCommerce
add_action('before_woocommerce_init', $this->declareHposCompatibility(...));
// Реєстрація сервісних ендпоінтів та слухачів подій
add_action('init', $this->registerServiceRoutes(...));
}
/**
* Повідомляємо ядру WooCommerce, що наш плагін на 100% сумісний із кастомними таблицями HPOS
* та новими Cart & Checkout блоками.
*/
public function declareHposCompatibility(): void
{
if (class_exists(FeaturesUtil::class)) {
// Декларуємо сумісність із High-Performance Order Storage (custom_order_tables)
FeaturesUtil::declare_compatibility('custom_order_tables', __FILE__, true);
// Декларуємо сумісність із новими Cart & Checkout Blocks
FeaturesUtil::declare_compatibility('cart_checkout_blocks', __FILE__, true);
}
}
public function registerServiceRoutes(): void
{
// Ініціалізація сервісного шару
}
}
/**
* 2. Сервіс ізольованої роботи із замовленнями на базі HPOS.
*/
final readonly class OrderTelemetryService
{
/**
* Вибирає замовлення за останні N годин за email клієнта з використанням B-Tree індексів HPOS.
*
* @return array<int, array<string, mixed>>
*/
public function findRecentCustomerOrders(string $billingEmail, int $hoursWindow = 24): array
{
$sanitizedEmail = sanitize_email($billingEmail);
if ($sanitizedEmail === '') {
return [];
}
$sinceTimestamp = time() - ($hoursWindow * 3600);
// КРИТИЧНО: Використовуємо WC_Order_Query замість WP_Query!
// На HPOS цей запит звернеться безпосередньо до wp_wc_orders та wp_wc_order_addresses
$query = new WC_Order_Query([
'limit' => 50,
'status' => ['wc-processing', 'wc-completed'],
'billing_email' => $sanitizedEmail,
'date_created' => '>=' . $sinceTimestamp,
'orderby' => 'date',
'order' => 'DESC',
'return' => 'objects', // Отримуємо типізовані об'єкти WC_Order
]);
/** @var WC_Order[] $orders */
$orders = $query->get_orders();
$payload = [];
foreach ($orders as $order) {
// Безпечний доступ виключно через методи CRUD-об'єкта
$payload[] = [
'orderId' => $order->get_id(),
'orderNumber' => $order->get_order_number(),
'status' => $order->get_status(),
'totalAmount' => (float) $order->get_total(),
'currency' => $order->get_currency(),
'customerPhone' => $order->get_billing_phone(),
'transactionId' => $order->get_transaction_id(),
'telemetryStatus' => (string) $order->get_meta('_agentic_telemetry_status', true),
'itemsCount' => $order->get_item_count(),
];
}
return $payload;
}
/**
* Атомарне оновлення метаданих замовлення з гарантією сумісності з HPOS.
*/
public function attachSecurityTelemetry(int $orderId, string $telemetryFingerprint): bool
{
// wc_get_order() автоматично використовує активний Data Store (HPOS чи CPT)
$order = wc_get_order($orderId);
if (!$order instanceof WC_Order) {
return false;
}
// КАТЕГОРИЧНО ЗАБОРОНЕНО: update_post_meta($orderId, ...) — зламає HPOS!
// ПРАВИЛЬНО: використовуємо вбудований CRUD метод об'єкта WC_Order
$order->update_meta_data('_agentic_telemetry_status', 'verified');
$order->update_meta_data('_agentic_fingerprint', sanitize_text_field($telemetryFingerprint));
$order->update_meta_data('_agentic_verified_at', gmdate('c'));
// Метод save() атомарно фіксує зміни в таблиці wp_wc_orders_meta
$order->save();
return true;
}
}
// Запуск ініціалізації шлюзу
(new HposEnterpriseBootstrap())->registerHooks();
Виконайте пошук по кодовій базі регулярним виразом: знайдіть усі виклики get_post_meta, update_post_meta, get_post та WP_Query, де фігурує shop_order, і перепишіть їх на wc_get_order() та WC_Order_Query.
В основному файлі кастомного плагіна або mu-plugin додайте виклик FeaturesUtil::declare_compatibility('custom_order_tables', __FILE__, true) на хуку before_woocommerce_init.
Перейдіть у WooCommerce -> Налаштування -> Додатково -> Функції. Увімкніть «Сховище замовлень високої продуктивності» в режимі синхронізації (Sync to postmeta).
Запустіть фоновий процес міграції існуючих замовлень. Після завершення перемкніть режим на «Авторитетне сховище замовлень HPOS» та відключіть дублювання в postmeta.