Какъв проблем решава Cache Product Objects
Всяко извикване на wc_get_product() създава нов WC_Product обект. WordPress вече кешира суровите данни – post data, meta, taxonomy terms – през собствения си object cache и стандартните post caching механизми. Проблемът не е в базата данни, а в процеса на хидрация: конструиране на обекта, задаване на свойства, зареждане на мета полета в структурата на класа. Тази операция отнема между 0.5 и 0.9 ms на продукт.
На product page с variable продукт и пет-шест активни разширения, един и същи продукт може да се зареди 8-12 пъти в рамките на единична HTTP заявка. Всяко зареждане минава през пълния цикъл на хидрация – дори данните вече да стоят в кеширащия слой на WordPress. За магазин с bundle продукти или subscription добавки, числото расте допълнително.
Cache Product Objects елиминира точно този overhead. Първото извикване на wc_get_product($id) минава по нормалния път и записва готовия обект в in-memory масив. Всяко следващо извикване за същото ID връща clone на кеширания обект вместо да минава отново през datastore-а.
Как работи на ниско ниво
Механизмът се намесва в WC_Product_Factory::get_product(). Преди да делегира към datastore, фабриката проверява вътрешен runtime масив (не persistent storage, не Redis, не база данни). Ако намери съвпадение по product ID, прави clone на обекта и го връща.
// Опростена илюстрация на логиката в WC_Product_Factory
$cached = ProductInstanceCache::get( $product_id );
if ( $cached ) {
return clone $cached;
}
$product = $datastore->read( $product_id );
ProductInstanceCache::set( $product_id, $product );
return $product;
clone е критичен детайл тук. Без него всяка модификация на обекта от един плъгин би се отразила навсякъде в request-а, което би довело до трудни за диагностициране бъгове. С clone всеки caller получава собствено копие на обекта, което може да модифицира свободно без странични ефекти.
Инвалидирането на кеша се задейства автоматично при стандартни WordPress и WooCommerce действия: clean_post_cache, updated_post_meta, added_post_meta, deleted_post_meta, woocommerce_updated_product_stock, woocommerce_updated_product_sales и при save() операции през product datastore. Ако данните минават през официалните API-та, кешът се изчиства коректно.
Активиране и конфигурация
Функцията е изключена по подразбиране и се включва от WooCommerce > Settings > Advanced > Features с отметка на Cache Product Objects. Налична е от WooCommerce 10.5 нагоре – ако не я виждате, проверете версията на плъгина.
# Проверка на WooCommerce версията от WP-CLI
wp option get woocommerce_version
# Очакван резултат: 10.5.0 или по-нова
Програмно може да се активира и чрез филтър:
// Програмно активиране (за staging/testing среда)
add_filter( 'woocommerce_feature_product_instance_caching_enabled', '__return_true' );
Разширенията на трети страни декларират съвместимост с тази функция по начина, познат от HPOS прехода в WooCommerce. Дори без изрична декларация от страна на плъгина, функцията се прилага глобално за всички product loads в магазина.
Реални бенчмаркове от WooCommerce екипа
Официалните тестове са направени с активен WooCommerce All Products for Subscriptions, който предизвиква допълнително зареждане на продукти при различни операции. Резултатите варират в зависимост от типа продукт и действието на потребителя.
Variable Product - View Product Page: -160ms до -227ms (~9-12%)
Variable Product - Add to Cart: -235ms до -250ms (~12-13%)
Bundle Product - Place Order: -165ms до -234ms (~6-12%)
Simple Product - Place Order: -22ms до -56ms (~2-6%)
Simple продуктите показват по-скромно подобрение, защото се зареждат по-рядко повторно в рамките на checkout. Variable и bundle продуктите печелят повече – variations и bundled items предизвикват множество wc_get_product() извиквания за едни и същи ID-та. Магазин само с прости продукти и без тежки разширения може изобщо да не забележи промяна.
Магазин с WooCommerce бисквитки, subscription добавки и custom pricing логика ще види осезаемо подобрение на checkout и product page response time. За магазини с над 500 variable продукта и 10+ активни разширения, спестените милисекунди се натрупват – особено при checkout, където WooCommerce зарежда продуктите от количката, прилага отстъпки, валидира наличности и калкулира данъци в рамките на един request.
Кога кешът може да доведе до проблеми
Директните SQL заявки са основният рисков фактор.
Ако разширение обновява product meta с $wpdb->update() без да извика clean_post_cache() или wp_cache_delete(), кешираният обект остава неактуален за остатъка от заявката. Следващото извикване на wc_get_product() ще върне стария обект от кеша, не обновените данни. При стандартен продуктов поток (admin save, REST API update, WooCommerce import) проблемът не възниква.
// ГРЕШЕН подход - кешът няма да се инвалидира
$wpdb->update(
$wpdb->postmeta,
array( 'meta_value' => '29.99' ),
array( 'post_id' => $product_id, 'meta_key' => '_price' )
);
// ПРАВИЛЕН подход - тригерира WordPress hooks
update_post_meta( $product_id, '_price', '29.99' );
// Или поне ръчно инвалидиране след директен SQL
clean_post_cache( $product_id );
WeakMap зависимости са друг ъглов случай, който засяга по-специфични разширения. Ако плъгин съхранява допълнителни данни за продуктов обект чрез WeakMap, clone операцията създава нов обект, който няма съответстващ запис в тази WeakMap. Към момента няма hook, който да се задейства при клониране от кеша, така че разработчиците на подобни плъгини трябва да преработят подхода си.
Взаимодействие с persistent object cache
Cache Product Objects и persistent object cache (Redis, Memcached) работят на различни слоеве и не се конкурират. Persistent кешът съхранява сурови данни между заявки – post rows, meta rows, option стойности. Product instance cache-ът работи само в рамките на единична заявка и пази вече конструирани PHP обекти.
Заявка 1:
wc_get_product(42)
-> WordPress object cache (Redis) -> post data, meta [HIT/MISS]
-> WC_Product hydration [~0.7ms]
-> Product Instance Cache: SET
wc_get_product(42) // второ извикване
-> Product Instance Cache: HIT -> clone [~0.05ms]
// Спестява 0.7ms хидрация
Заявка 2 (нов HTTP request):
// Product Instance Cache е празен
wc_get_product(42)
-> WordPress object cache (Redis) -> post data, meta [HIT]
-> WC_Product hydration [~0.7ms]
За оптимална производителност двата кеширащи слоя се допълват. Redis елиминира SQL заявки между page loads, а product instance cache елиминира повторна хидрация в рамките на единична заявка. Сайтове, които разчитат на page-level кеширане, ще имат по-малко полза от тази функция, защото PHP изобщо не се изпълнява при пълен cache hit на ниво Nginx или Varnish.
Transients и product data – различен механизъм
WooCommerce използва transients за различни продуктови данни: цени на вариации, свързани продукти, product counts по категории. Тези transients са persistent – записват се в wp_options таблицата (или в Redis, ако има external object cache). Изчистват се ръчно от WooCommerce > Status > Tools > Clear Transients или програмно с wc_delete_product_transients().
// Изчистване на transients за конкретен продукт
wc_delete_product_transients( $product_id );
// Автоматично изчистване при промяна на свойства
add_action( 'woocommerce_product_object_updated_props', function( $product ) {
wc_delete_product_transients( $product->get_id() );
});
Product instance cache-ът няма нищо общо с transients. Не записва данни в базата, не персистира между заявки и не изисква ръчно изчистване. Двата механизма решават различни проблеми и не конфликтуват помежду си при стандартна конфигурация. WooCommerce 10.5 подобрява и transient кеширането за вариационни цени с нов алгоритъм за хеширане, който намалява ненужните инвалидации.
Диагностика с Query Monitor
За да проверите дали кешът работи на вашия сайт, инсталирайте Query Monitor. В секцията Object Cache ще видите броя cache hits и misses за различни групи. По-конкретно, следете за повторни извиквания на wc_get_product() с еднакви ID-та в рамките на една page load.
// Debug log за проследяване на product loads
add_action( 'woocommerce_before_single_product', function() {
add_filter( 'woocommerce_product_class', function( $classname, $product_type, $product_id ) {
error_log( sprintf(
'[ProductCache] Loading product #%d (%s) at %.4f',
$product_id, $product_type, microtime( true )
));
return $classname;
}, 10, 3 );
});
Ако след активиране на функцията видите, че определен продукт се зарежда само веднъж в лога (вместо 5-6 пъти), кешът работи коректно. Следващите зареждания минават през clone операцията, която не тригерира product_class филтъра и съответно не генерира допълнителни записи.
Стъпки за безопасно активиране в production
Активирайте функцията първо на staging среда. Проверете основните потоци: product page, add to cart, checkout, order confirmation. Обърнете внимание на цените – ако custom pricing плъгин разчита на директни SQL заявки, цените може да се покажат неактуални.
За WP-CLI потребители, бърз тест на производителността преди и след:
# Измерване на response time преди активиране
wp eval 'update_option("woocommerce_feature_product_instance_caching_enabled","no");'
ab -n 50 -c 1 https://yoursite.com/product/your-variable-product/
# Активиране и повторен тест
wp eval 'update_option("woocommerce_feature_product_instance_caching_enabled","yes");'
ab -n 50 -c 1 https://yoursite.com/product/your-variable-product/
Сравнете средните стойности на Time per request. Разликата ще е най-видима при variable продукти с много вариации и при bundle продукти с десетки подпродукти. Ако видите регресия или грешки при checkout, деактивирайте функцията и проверете за несъвместими разширения чрез debug log-а.
Често задавани въпроси
-
Какво точно кешира Cache Product Objects в WooCommerce?
Функцията кешира напълно инстанцираните WC_Product обекти в паметта за времето на текущата HTTP заявка. Самите данни от базата (post data, meta, taxonomy terms) вече се кешират от WordPress – тази функция спестява повторната хидрация на обектите.
-
Трябва ли ми Redis или Memcached, за да работи Cache Product Objects?
Не. Кешът е in-memory и живее само в рамките на единична заявка. Не зависи от persistent object cache като Redis или Memcached и не записва нищо в базата данни.
-
Как да включа Cache Product Objects?
Отидете в WooCommerce > Settings > Advanced > Features и активирайте опцията Cache Product Objects. Функцията е налична от WooCommerce 10.5 нагоре.
-
Може ли Cache Product Objects да счупи плъгини от трети страни?
Ако плъгин променя продуктови данни с директни SQL заявки без да извика clean_post_cache(), кешираният обект ще остане неактуален до края на заявката. Повечето плъгини, които използват стандартните WooCommerce API-та, няма да имат проблем.
-
Колко подобрение на производителността да очаквам от Cache Product Objects?
Зависи от броя разширения и колко пъти се зарежда един и същи продукт в рамките на заявка. Официалните бенчмаркове показват между 2% и 13% ускорение при различни операции – от прост checkout до зареждане на variable product страница.
