Диагностика задачи: зачем менять цену товара в корзине
В WooCommerce базовая цена товара задаётся в карточке продукта. Однако часто возникает необходимость динамически изменять стоимость товара в корзине — например, при покупке определённого количества, комбинации товаров, для конкретной роли пользователя или при активации промокода. Стандартный функционал WooCommerce не позволяет просто менять цену товара после добавления в корзину, поэтому нужно использовать хуки и фильтры.
Как изменить цену товара в корзине через хук woocommerce_before_calculate_totals
Для изменения цены в корзине используется хук woocommerce_before_calculate_totals. В этом хуке можно перебрать все товары корзины и задать для них новую цену.
Пример: меняем цену товара с ID 123 на 500 рублей, если в корзине больше 3 единиц этого товара.
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;
foreach ($cart->get_cart() as $cart_item_key => $cart_item) {
$product = $cart_item['data'];
if ($product->get_id() == 123) {
if ($cart_item['quantity'] > 3) {
$new_price = 500; // новая цена
$product->set_price($new_price);
}
}
}
}Пояснения к коду
is_admin()иDOING_AJAX— защита, чтобы код не срабатывал в админке и не ломал обновления корзины.- Метод
set_price()меняет цену товара для текущего объекта корзины, не затрагивая базовую цену в базе.
Пошаговое решение задачи с условиями
- Определить условие, при котором нужно менять цену (например, количество, роль пользователя, наличие другого товара).
- Добавить код с хуком
woocommerce_before_calculate_totalsв файлfunctions.phpвашей темы или в кастомный плагин. - Обязательно проверить, что код не срабатывает в админке и не конфликтует с ajax-запросами.
- Протестировать работу в корзине, изменяя количество товаров, чтобы увидеть изменение цены.
Проверка результата после внедрения
- Добавьте в корзину товар с ID, указанным в коде (например, 123).
- Увеличьте количество товара больше порогового (например, 4).
- Обновите страницу корзины и убедитесь, что цена изменилась на заданную (500 рублей).
- Убедитесь, что в чекауте и заказе изменённая цена сохраняется.
- Проверьте, что в админке и при просмотре товара цена осталась неизменной.
Частые ошибки при изменении цены в корзине и их исправление
- Изменение цены в админке: если не добавить проверку
is_admin() && !DOING_AJAX, цена может изменяться и в админке, что приводит к ошибкам. - Неверное использование объекта товара: менять цену нужно через
$cart_item['data']->set_price(), а не напрямую в массиве. - Конфликт с другими плагинами, меняющими цены: проверьте приоритет хука (рекомендуется 20 или выше).
- Цена не сохраняется в заказе: убедитесь, что не используется кеширование и что цена корректно передаётся в заказ WooCommerce.
Практические советы по безопасности и производительности
- Не используйте этот код для изменения цены в публичном доступе без проверки прав пользователя. Это может привести к обходу цен.
- Избегайте сложных и тяжёлых вычислений внутри хука — это влияет на скорость загрузки корзины.
- Если нужно менять цену для роли пользователя, используйте
current_user_can()илиwp_get_current_user(). - Проверяйте совместимость с кеширующими плагинами, чтобы изменения цены не кешировались.
Сравнение вариантов изменения цены в WooCommerce
| Вариант | Описание | Плюсы | Минусы |
|---|---|---|---|
Использование woocommerce_before_calculate_totals | Изменение цены в объекте товара корзины | Гибко, работает с любыми условиями, без плагинов | Требует программирования, может конфликтовать с другими плагинами |
| Плагины для динамического ценообразования | Готовые решения с настройками через админку | Простота использования, поддержка, меньше кода | Может быть дорого, меньше гибкости, нагрузка |
| Изменение цены через метаданные и фильтры | Настройка цен через мета-поля и фильтры | Позволяет хранить индивидуальные цены | Сложнее в настройке, требует кастомного кода |
Дополнительный пример: изменение цены для пользователей с ролью "оптовик"
add_action('woocommerce_before_calculate_totals', 'change_price_for_wholesale_users', 20, 1);
function change_price_for_wholesale_users($cart) {
if (is_admin() && !defined('DOING_AJAX')) return;
$user = wp_get_current_user();
if (in_array('wholesaler', (array) $user->roles)) {
foreach ($cart->get_cart() as $cart_item) {
$product = $cart_item['data'];
$original_price = $product->get_regular_price();
$discounted_price = $original_price * 0.8; // скидка 20%
$product->set_price($discounted_price);
}
}
}