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 индексу за менее 2 мс, не затрагивая контентную базу данных 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-полей.
Выполните поиск по кодовой базе регулярным выражением: найдите все вызовы 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.
Какой хук ядра WooCommerce является ЕДИНСТВЕННО допустимым для вызова FeaturesUtil::declare_compatibility('custom_order_tables', ...) и почему?
В инженерных проектах Fullstack Agentic Lab архитектура HPOS и Store API является обязательным стандартом для:
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();
Разработчик выполнил поиск завершенных заказов через new WP_Query(['post_type' => 'shop_order', 'post_status' => 'wc-completed']) в магазине с включенным авторитетным режимом HPOS. Что вернет этот запрос и как правильно решить задачу?