Диагностика задачи: зачем менять цену товара программно
В WooCommerce часто требуется динамически менять цену товара, например, при определённых условиях: скидка на определённую категорию, изменение цены в зависимости от количества в корзине или время акции. Основная проблема — правильное внедрение логики, чтобы цена менялась только в нужных случаях и корректно отображалась на фронтенде и в заказах.
Как WooCommerce рассчитывает цену товара
WooCommerce использует метод get_price() объекта WC_Product для вывода цены. Чтобы изменить стоимость, нужно перехватить момент получения цены и подставить свою.
Для этого подходит хук woocommerce_product_get_price и woocommerce_product_get_regular_price. Они позволяют модифицировать цену товара на лету без изменения в базе.
Пошаговое решение: пример автоматического снижения цены для категории "Скидки" при заказе более 3 штук
Задача: если в корзине больше 3 единиц товара из категории "discount-category", цена на эти товары уменьшается на 15%.
Шаг 1. Добавляем фильтр для изменения цены товара
add_filter('woocommerce_product_get_price', 'custom_dynamic_price', 10, 2);
add_filter('woocommerce_product_get_regular_price', 'custom_dynamic_price', 10, 2);
function custom_dynamic_price($price, $product) {
if (is_admin() && !defined('DOING_AJAX')) {
return $price; // не трогаем в админке
}
// Получаем ID товара
$product_id = $product->get_id();
// Проверяем наличие товара в корзине с нужной категорией
$cart = WC()->cart;
if (!$cart) return $price;
$total_quantity = 0;
// Итерация по корзине
foreach ($cart->get_cart() as $cart_item) {
$cart_product = $cart_item['data'];
$categories = wp_get_post_terms($cart_product->get_id(), 'product_cat', array('fields' => 'slugs'));
if (in_array('discount-category', $categories)) {
$total_quantity += $cart_item['quantity'];
}
}
// Если товаров категории в корзине больше 3, уменьшаем цену
if ($total_quantity > 3) {
// Уменьшаем цену на 15%
$price = $price * 0.85;
}
return $price;
}
Шаг 2. Проверяем отображение цены на странице товара и в корзине
- Откройте страницу товара из категории
discount-category. - Добавьте 4 и более единиц этого товара в корзину.
- Убедитесь, что цена товара снизилась на 15% и отображается корректно в корзине и на странице оформления заказа.
Проверка результата после внедрения
Чтобы проверить, что всё работает, сделайте следующее:
- Очистите корзину и кэш сайта.
- Добавьте в корзину 3 товара из категории
discount-category— цена должна быть без скидки. - Добавьте 4-й товар — цена должна автоматически измениться с учётом скидки.
- Проверьте, что в админке цены не меняются, чтобы избежать путаницы при редактировании товаров.
Частые ошибки и как их исправить
- Цена не меняется в корзине: проверьте, что фильтры подключены правильно и функция учитывает корзину
WC()->cart. Важно, чтобы корзина была инициализирована, иначе цена не обновится. - Изменения цены применяются в админке: добавьте проверку
is_admin()и!defined('DOING_AJAX')чтобы не ломать админку. - Некорректный расчёт скидки: учитывайте, что в корзине могут быть разные товары, и суммируйте количество только по нужной категории.
- Цена отображается неверно после кеширования: если используете кеширование страниц, настройте исключения для страниц корзины и оформления заказа.
Практические советы по производительности и безопасности
- Используйте минимальное количество вызовов функций в циклах, например, кешируйте результаты
wp_get_post_terms. - Не сохраняйте изменённые цены в базу, чтобы избежать рассинхронизации — лучше менять цену на лету через фильтры.
- Проверяйте, что код не влияет на REST API и админ-панель, чтобы избежать ошибок при редактировании.
- Если используете сторонние плагины кеширования, отключайте кеширование для страниц корзины (
cart) и оформления заказов (checkout).
Сравнение подходов: фильтры vs. изменение метаполей товара
| Метод | Плюсы | Минусы | Когда использовать |
|---|---|---|---|
Фильтры woocommerce_product_get_price | Изменения на лету, не затрагивают базу, легко отменить | Сложнее отследить, зависит от инициализации корзины | Динамические скидки, акции во время сессии |
| Изменение метаполей товара (update_post_meta) | Простая реализация, видна в админке | Риск рассинхронизации, постоянные изменения в базе | Постоянное изменение цены, например, для распродаж |