Диагностика задачи: зачем менять стоимость товара в корзине программно
В WooCommerce часто требуется изменить стоимость товара в корзине не просто по фиксированной скидке, а по сложным условиям — например, в зависимости от пользовательских ролей, выбранных атрибутов товара, количества в корзине или специальных промоакций. Стандартными средствами WooCommerce такие сценарии реализовать сложно, поэтому приходится писать собственный код с использованием хуков.
Основные сценарии изменения цены в корзине
- Скидка на товар при определённом количестве (например, «3-й товар со скидкой 50%»)
- Изменение цены в зависимости от атрибутов или вариаций
- Скидка или наценка для определённых ролей пользователей (оптовики, подписчики и т.п.)
- Изменение цены в корзине по промокоду с дополнительными условиями
Чтобы проверить, что цена меняется, нужно внимательно следить за итогом в корзине и на странице оформления заказа, а также учитывать возможные кеширующие плагины и кэш браузера.
Пошаговое решение: изменение цены товара в корзине через хук woocommerce_before_calculate_totals
Шаг 1: подключаем функцию в файл темы functions.php или в собственный плагин.
add_action('woocommerce_before_calculate_totals', 'custom_change_cart_item_price', 20, 1);
function custom_change_cart_item_price( $cart ) {
if ( is_admin() && ! defined( 'DOING_AJAX' ) ) {
return;
}
// Проверяем, что корзина не пуста
if ( did_action( 'woocommerce_before_calculate_totals' ) >= 2 ) {
return;
}
foreach ( $cart->get_cart() as $cart_item_key => $cart_item ) {
$product = $cart_item['data'];
$original_price = $product->get_price();
// Пример условия: если количество товара >= 3, даём скидку 20%
if ( $cart_item['quantity'] >= 3 ) {
$new_price = $original_price * 0.8; // скидка 20%
$product->set_price( $new_price );
}
// Дополнительное условие: для пользователей с ролью 'wholesale_customer' скидка 30%
$user = wp_get_current_user();
if ( in_array( 'wholesale_customer', (array) $user->roles ) ) {
$new_price = $original_price * 0.7;
$product->set_price( $new_price );
}
// Можно добавить и другие условия по атрибутам, метаданным и т.п.
}
}Шаг 2: Очищаем кеш WooCommerce, браузера, если есть кэширующие плагины, чтобы изменения отобразились корректно.
Пояснения к коду
- Хук
woocommerce_before_calculate_totalsвызывается до подсчёта итоговой стоимости корзины. - Метод
set_price()меняет цену товара для текущего экземпляра в корзине, не трогая цену в базе. - Обязательно проверяем, что код не выполняется в админке вне AJAX (чтобы не сломать админские операции).
- Проверяем, чтобы хук не сработал несколько раз подряд (дважды), чтобы избежать багов.
Проверка результата после внедрения
- Добавьте в корзину товар с количеством, подходящим под условие (например, 3 штуки).
- Зайдите на страницу корзины и убедитесь, что цена изменилась (отобразилась с учётом скидки).
- Проверьте оформление заказа: итоговая сумма должна совпадать с изменённой ценой.
- Проверьте под разными ролями пользователей (если условие зависит от ролей).
- Отключите кэш и очистите все кеши, если изменения не видны.
Частые ошибки и как их исправить
- Цена не меняется после добавления кода: возможно, кэш не очищен или хук вызывается слишком рано/поздно. Проверьте приоритет и очистите кеш.
- Цена меняется у всех товаров, а должна для определённых: проверьте условия в коде, возможно, логика фильтрации не корректна.
- Ошибка с двойным применением скидки: убедитесь, что проверка
did_action( 'woocommerce_before_calculate_totals' ) < 2есть в функции. - Цена изменилась в базе данных товара: используйте
set_price()у объекта товара в корзине, а не меняйте цену напрямую в базе. - Проблемы с совместимостью плагинов кеширования: добавьте динамический фрагмент кеша для страницы корзины и оформления заказа.
Практические советы по безопасности и производительности
- Не используйте слишком сложные вычисления внутри хука — это может замедлить загрузку корзины.
- Всегда проверяйте, что пользователь авторизован, если скидки зависят от ролей.
- При работе с пользовательскими метаданными кешируйте результаты запросов, если используете их в условиях.
- Тестируйте изменения на тестовой копии сайта, чтобы избежать ошибок на живом магазине.
Сравнение способов реализации изменения цены товара в корзине
| Метод | Плюсы | Минусы | Когда использовать |
|---|---|---|---|
Хук woocommerce_before_calculate_totals и set_price() | Гибкость, точечное изменение цены, не требует плагинов | Требует навыков программирования, возможны ошибки при неправильной логике | Когда нужно динамическое изменение цены по сложным условиям |
| Плагины скидок (например, WooCommerce Dynamic Pricing) | Простая настройка, много готовых условий, поддержка | Платные решения, меньше гибкости, возможны конфликты с другими плагинами | Для стандартных промо-акций и массовых скидок |
| Использование пользовательских метаполей и фильтров цены | Можно хранить данные о скидках в метаполях, интеграция с внешними системами | Сложнее реализовать логику, требует поддержки | При интеграции с CRM или ERP |