Проблема: как автоматически менять цену товара в WooCommerce при выборе доставки
В стандартном WooCommerce цена товара фиксирована и не зависит от выбранного способа доставки. Но бывают задачи, когда нужно изменить стоимость товара в зависимости от способа доставки — например, добавить наценку при экспресс-доставке или скидку при самовывозе. В этом сценарии мы рассмотрим, как программно менять цену товара в корзине и на странице товара в зависимости от выбранного способа доставки.
Диагностика задачи: что нужно учесть
- Изменение цены должно происходить динамически, без перезагрузки страницы (желательно AJAX).
- Изменённая цена должна отображаться на странице товара, в корзине и на этапе оформления заказа.
- Изменения должны применяться только к конкретному товару или группе товаров.
- Необходимо корректно учитывать налоговые ставки и отображать итоговую сумму.
- Нужно избежать конфликтов с другими плагинами, особенно с кэшированием.
Пошаговое решение
1. Добавляем выбор способа доставки на страницу товара
Для демонстрации добавим на страницу товара селект с вариантами доставки. Обычно выбор доставки происходит на странице корзины/оформления, но для примера покажем на товаре.
add_action('woocommerce_before_add_to_cart_button', function() {
echo '<p><label for="delivery_method">Выберите способ доставки:</label>';
echo '<select id="delivery_method" name="delivery_method">';
echo '<option value="standard">Стандартная доставка</option>';
echo '<option value="express">Экспресс-доставка (+500 руб.)</option>';
echo '<option value="pickup">Самовывоз (-100 руб.)</option>';
echo '</select></p>';
});2. Сохраняем выбранный способ доставки при добавлении в корзину
add_filter('woocommerce_add_cart_item_data', function($cart_item_data, $product_id, $variation_id) {
if (isset($_POST['delivery_method'])) {
$cart_item_data['delivery_method'] = sanitize_text_field($_POST['delivery_method']);
// Чтобы товар с разной доставкой не объединился
$cart_item_data['unique_key'] = md5(microtime().rand());
}
return $cart_item_data;
}, 10, 3);3. Изменяем цену товара в корзине в зависимости от способа доставки
add_action('woocommerce_before_calculate_totals', function($cart) {
if (is_admin() && !defined('DOING_AJAX')) return;
foreach ($cart->get_cart() as $cart_item) {
if (isset($cart_item['delivery_method'])) {
$price = $cart_item['data']->get_regular_price();
switch ($cart_item['delivery_method']) {
case 'express':
$price += 500; // наценка
break;
case 'pickup':
$price -= 100; // скидка
if ($price < 0) $price = 0;
break;
case 'standard':
default:
break;
}
$cart_item['data']->set_price($price);
}
}
});4. Отображаем выбранный способ доставки в корзине и в заказе
add_filter('woocommerce_get_item_data', function($item_data, $cart_item) {
if (!empty($cart_item['delivery_method'])) {
$delivery_names = [
'standard' => 'Стандартная доставка',
'express' => 'Экспресс-доставка',
'pickup' => 'Самовывоз',
];
$item_data[] = [
'key' => 'Способ доставки',
'value' => $delivery_names[$cart_item['delivery_method']] ?? $cart_item['delivery_method'],
];
}
return $item_data;
}, 10, 2);5. Добавляем выбранный способ доставки в метаданные заказа
add_action('woocommerce_add_order_item_meta', function($item_id, $values) {
if (!empty($values['delivery_method'])) {
wc_add_order_item_meta($item_id, 'Способ доставки', $values['delivery_method']);
}
}, 10, 2);Проверка результата
- Откройте страницу товара, выберите способ доставки и добавьте товар в корзину.
- Перейдите в корзину — цена товара должна измениться согласно выбранному способу доставки.
- В корзине под каждым товаром должно отображаться выбранное значение способа доставки.
- При оформлении заказа проверьте, что выбранный способ доставки сохраняется в деталях заказа.
- Для проверки можно добавить несколько товаров с разными способами доставки — они не должны объединяться.
Частые ошибки и как их исправить
- Цена не меняется в корзине: Проверьте, что хук
woocommerce_before_calculate_totalsне прерывается другими плагинами и что функция не возвращает преждевременно на админке. - Товар объединяется в корзине несмотря на разные способы доставки: Не забудьте добавить уникальный ключ в
cart_item_data, чтобы WooCommerce считал товары разными. - Изменения не отображаются на странице товара: Для динамического изменения цены на странице товара потребуется реализовать AJAX-обработчик и JavaScript для перезагрузки цены без обновления страницы.
- Неверное отображение в заказах: Проверьте, что метаданные корректно добавляются с помощью
wc_add_order_item_meta.
Практические советы по безопасности и производительности
- Всегда используйте
sanitize_text_fieldили аналогичные функции для обработки данных из$_POST. - Избегайте тяжелых операций внутри хуков изменения цены, так как они вызываются несколько раз в процессе оформления заказа.
- При использовании кэширования страниц убедитесь, что корзина и цены корректно обновляются для каждого пользователя.
- Если необходимо отображать изменённую цену на странице товара в реальном времени, реализуйте AJAX-запросы с nonce для безопасности.
Сравнение способов реализации
| Метод | Плюсы | Минусы |
|---|---|---|
Изменение цены в корзине через хук woocommerce_before_calculate_totals | Просто, работает для всех товаров, меняет цену в корзине и заказе | Не влияет на страницу товара, нет динамического обновления цены до добавления в корзину |
| Динамическое изменение цены на странице товара через AJAX | Показывает актуальную цену сразу, улучшает UX | Сложнее в реализации, требует JS и AJAX, повышает нагрузку |
| Использование плагинов для адаптивных цен | Готовые решения с UI для настройки | Может быть дорого, нагрузка на сайт, ограниченная гибкость |