Диагностика задачи: зачем менять цену товара в корзине
В стандартном WooCommerce цена товара рассчитывается на основе установленных прайс-листов и скидок. Однако часто возникает необходимость динамически менять стоимость товара в корзине в зависимости от условий: количество, роль пользователя, купоны, даты и т.д. Например, сделать скидку на второй товар или добавить наценку при определённом способе доставки.
Если вы столкнулись с задачей изменения цены товара на лету, без изменения цены в базе и без плагинов, то правильный подход — использовать хук woocommerce_before_calculate_totals.
Как изменить цену товара в корзине через хук woocommerce_before_calculate_totals
Этот хук вызывается перед подсчётом итоговой суммы корзины. Вы можете перебрать все товары в корзине и изменить цену каждого или отдельных товаров по условию.
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 ) {
// Пример: изменить цену для товара с ID 123
if ( $cart_item['product_id'] == 123 ) {
// Задаём новую цену
$new_price = 500; // новая цена в валюте магазина
$cart_item['data']->set_price( $new_price );
}
// Можно добавить другие условия
// Например, если количество товара > 3, даём скидку 10%
if ( $cart_item['quantity'] > 3 ) {
$original_price = $cart_item['data']->get_regular_price();
$discounted_price = $original_price * 0.9;
$cart_item['data']->set_price( $discounted_price );
}
}
}Объяснение кода
- Проверяем, что код не выполняется в админке или при AJAX-запросах, чтобы избежать ошибок.
- Ограничиваем повторное выполнение функции (важно, чтобы не было двойного применения цен).
- Перебираем товары в корзине и меняем цену через
set_price()у объектаWC_Product.
Пошаговое решение для изменения цены по роли пользователя
Допустим, нужно сделать скидку 15% для пользователей с ролью "оптовик".
add_action('woocommerce_before_calculate_totals', 'discount_for_wholesale_users', 20, 1);
function discount_for_wholesale_users( $cart ) {
if ( is_admin() && ! defined('DOING_AJAX') ) {
return;
}
if ( did_action( 'woocommerce_before_calculate_totals' ) >= 2 ) {
return;
}
// Проверяем роль пользователя
if ( current_user_can('wholesale') ) {
foreach ( $cart->get_cart() as $cart_item_key => $cart_item ) {
$original_price = $cart_item['data']->get_regular_price();
$discount_price = $original_price * 0.85; // скидка 15%
$cart_item['data']->set_price( $discount_price );
}
}
}Как проверить, что цена изменилась правильно
- Добавьте тестовый товар с ID, указанным в условии.
- Перейдите в корзину, убедитесь, что цена товара изменилась согласно вашему коду.
- Проверьте, что итоговая сумма и налоговые расчёты соответствуют изменённой цене.
- Если изменяете по роли, войдите под нужным пользователем.
- Проверьте работу на фронтенде и в админке (заказы), чтобы избежать конфликтов.
Частые ошибки при изменении цены в корзине и как их избежать
- Двойное применение скидок: если не ограничить вызов функции, цена будет меняться несколько раз. Используйте проверку
did_action(). - Изменение цены в админке: влияет на отображение заказа и может привести к конфликтам, проверяйте
is_admin(). - Изменение цены товара, а не вариации: при работе с вариациями используйте
$cart_item['variation_id']или проверяйте объектWC_Product. - Не обновляется итоговая сумма: всегда меняйте цену через метод
set_price()объекта товара, а не напрямую в массиве.
Практические советы для производительности и безопасности
- Не используйте тяжелые операции в хуке
woocommerce_before_calculate_totals, так как он вызывается при каждом изменении корзины. - Для сложных условий кэшируйте результаты, например, роли пользователя или внешние данные.
- Тестируйте изменения с отключенными плагинами кеширования, чтобы убедиться, что цены меняются корректно.
- Обязательно проверяйте совместимость с платежными шлюзами и плагинами скидок, чтобы избежать ошибок при оплате.
Сравнение методов изменения цены товара в корзине
| Метод | Описание | Плюсы | Минусы |
|---|---|---|---|
Хук woocommerce_before_calculate_totals |
Изменение цены товара динамически перед подсчётом суммы | Гибкость, не требует плагинов, работает с любыми условиями | Сложность при больших корзинах, требует аккуратного кода |
| Плагины скидок и наценок | Готовые решения для скидок и условий | Простота настройки, поддержка | Могут конфликтовать, ограничены по кастомизации |
| Изменение цены в базе товара | Редактирование цены товара напрямую | Простота | Меняет цену для всех, не подходит для условных скидок |