Проблема: необходимость менять цену товара в зависимости от выбранного способа доставки
В стандартном WooCommerce нет встроенной функции, которая позволяла бы менять стоимость товара в корзине динамически в зависимости от выбранного метода доставки. Часто это требуется для корректного расчёта стоимости, например, для доставки с разными тарифами или дополнительными сборами.
Диагностика задачи
Перед решением важно понять, какая именно логика изменения стоимости требуется:
- Изменять цену товара на фиксированную сумму или процент;
- Изменять общую стоимость заказа;
- Добавлять скрытые сборы на уровне товара;
- Применять изменение только к определённым товарам или категориям;
- Реагировать на выбор конкретного способа доставки.
Для проверки выбранного способа доставки можно использовать хук woocommerce_checkout_update_order_review или отслеживать данные из сессии WooCommerce.
Пошаговое решение: пример изменения цены товара при выборе способа доставки
1. Отслеживаем выбор способа доставки через AJAX
WooCommerce при выборе способа доставки обновляет данные через AJAX. Можно подключиться к этому событию и сохранить выбранный метод в сессии:
add_action('woocommerce_checkout_update_order_review', 'save_chosen_shipping_method');
function save_chosen_shipping_method($posted_data) {
parse_str($posted_data, $output);
if (!empty($output['shipping_method'])) {
WC()->session->set('chosen_shipping_method', $output['shipping_method'][0]);
}
}2. Изменяем цену товара в корзине перед расчётом итогов
Используем хук woocommerce_before_calculate_totals, чтобы динамически менять цену товара:
add_action('woocommerce_before_calculate_totals', 'change_product_price_based_on_shipping', 20, 1);
function change_product_price_based_on_shipping($cart) {
if (is_admin() && !defined('DOING_AJAX')) return;
$chosen_shipping = WC()->session->get('chosen_shipping_method');
if (!$chosen_shipping) return;
foreach ($cart->get_cart() as $cart_item_key => $cart_item) {
$product = $cart_item['data'];
$original_price = $product->get_regular_price();
// Пример логики: если выбран способ доставки "flat_rate:5" — увеличиваем цену на 10%
if ($chosen_shipping === 'flat_rate:5') {
$new_price = $original_price * 1.10; // +10%
$product->set_price($new_price);
} else {
// Сбрасываем цену, если другой способ доставки
$product->set_price($original_price);
}
}
}Проверка результата
- Добавьте товар в корзину и перейдите к оформлению заказа.
- Выберите способ доставки с ID
flat_rate:5(замените на актуальный ID вашего способа). - Проверьте, что цена товара изменилась на 10%.
- Выберите другой способ доставки — цена должна вернуться к исходной.
- Обновите страницу и убедитесь, что изменения сохраняются корректно.
Частые ошибки и их исправление
- Цена не меняется в корзине или на странице оформления заказа. Проверьте, что хук
woocommerce_before_calculate_totalsподключён с приоритетом выше 10 (чтобы перекрывать другие изменения). Также убедитесь, что сессия WooCommerce корректно сохраняет выбранный способ доставки. - Изменения не сохраняются при обновлении страницы. Возможно, сессия не была сохранена или выбран способ доставки сбрасывается. Проверьте работу функции сохранения в сессии и правильность ключа.
- Ошибка на странице админки или при AJAX-запросах. Добавьте проверку
if (is_admin() && !defined('DOING_AJAX')) return;в обработчик изменения цены, чтобы избежать ошибок в админке.
Практические советы по безопасности и производительности
- Изменяйте цену товара только в оперативной памяти объекта
WC_Productв корзине, не сохраняйте изменения в базе данных. - Не используйте жёсткие ID способов доставки — получайте их динамически или документируйте, чтобы не забыть.
- Минимизируйте количество вычислений в цикле корзины для оптимальной производительности.
- Для более сложных сценариев рассмотрите использование пользовательских сборов (fees), если изменение цены товара не подходит.
Сравнение подходов
| Способ | Плюсы | Минусы |
|---|---|---|
Изменение цены товара через woocommerce_before_calculate_totals | Гибко, напрямую меняет цену, отображается в корзине | Можно запутать пользователя, влияет на отчёты и аналитики |
| Добавление дополнительного сбора (fee) с учётом доставки | Прозрачно отделяет стоимость доставки от товара, проще для отчётов | Не меняет цену товара, требует дополнительной настройки отображения |
| Использование плагинов для динамического ценообразования | Расширенный функционал, готовые решения | Дополнительная нагрузка, возможны конфликты, платные решения |