Проблема: как динамически менять стоимость доставки в WooCommerce по регионам и весу заказа
В стандартных настройках WooCommerce можно задать стоимость доставки для регионов, но сложно учесть одновременно регион и вес заказа без дополнительных плагинов. Часто требуется, чтобы доставка для одного региона стоила, например, 300 рублей до 5 кг, а для другого региона — 500 рублей при аналогичном весе. Варианты плагинов часто слишком тяжелые или не подходят по функционалу. В этой статье разберем, как реализовать изменение стоимости доставки программно с помощью хуков WooCommerce.
Диагностика проблемы: почему стандартная настройка не подходит
В WooCommerce есть возможность задать зоны доставки и методы для них, но:
- Методы доставки обычно фиксируют цену или зависят от веса, но не учитывают регион и вес одновременно.
- Плагины для расширенного расчета доставки часто платные, имеют избыточный функционал и нагрузку.
- Настройка тарифов вручную в админке становится громоздкой при множестве регионов и весовых категорий.
Поэтому лучший путь — использовать хук woocommerce_package_rates для программного изменения стоимости доставки после расчета.
Пошаговое решение: реализация автоматической корректировки стоимости доставки
1. Получаем регион покупателя
Обычно регион определяется по адресу доставки в заказе. В коде это можно получить через объект $package в хуке woocommerce_package_rates:
add_filter('woocommerce_package_rates', 'custom_change_shipping_cost_by_region_and_weight', 10, 2);В функции $package['destination']['state'] или $package['destination']['country'] — регион и страна доставки.
2. Получаем вес заказа
Вес заказа в килограммах можно получить через сумму веса товаров в корзине:
function get_cart_weight() {
$weight = 0;
foreach (WC()->cart->get_cart() as $cart_item) {
$weight += floatval($cart_item['data']->get_weight()) * $cart_item['quantity'];
}
return $weight;
}3. Меняем стоимость доставки
Далее меняем цену для каждого метода доставки в зоне в зависимости от региона и веса:
function custom_change_shipping_cost_by_region_and_weight($rates, $package) {
$region = $package['destination']['state']; // Или 'country' если нужно
$weight = 0;
foreach (WC()->cart->get_cart() as $cart_item) {
$weight += floatval($cart_item['data']->get_weight()) * $cart_item['quantity'];
}
foreach ($rates as $rate_id => $rate) {
// Пример условий для региона и веса
if ($region === 'RU-MOW') { // Москва
if ($weight <= 5) {
$rates[$rate_id]->cost = 300; // 300 руб до 5 кг
} else {
$rates[$rate_id]->cost = 500; // 500 руб свыше 5 кг
}
} elseif ($region === 'RU-SPE') { // Санкт-Петербург
if ($weight <= 5) {
$rates[$rate_id]->cost = 350;
} else {
$rates[$rate_id]->cost = 550;
}
} else {
// Для других регионов оставить стандартную цену или задать свою
$rates[$rate_id]->cost = 600;
}
}
return $rates;
}
add_filter('woocommerce_package_rates', 'custom_change_shipping_cost_by_region_and_weight', 10, 2);Проверка результата после внедрения
- Добавьте товары с разным весом в корзину.
- Укажите адрес доставки с разными регионами (Москва, Санкт-Петербург, другие).
- На странице оформления заказа проверьте стоимость доставки — она должна менять цену в соответствии с заданными условиями.
- Для отладки можно временно добавить
error_log()внутри функции, чтобы выводить вычисленные значения региона и веса.
Частые ошибки и как исправить
- Регион не определяется корректно: Проверьте, что в
$package['destination']['state']приходит нужное значение. Иногда стоит использовать$package['destination']['city']илиcountry, в зависимости от настроек зоны доставки. - Вес товара не задан или не в килограммах: Убедитесь, что у товаров в WooCommerce заполнено поле «Вес» (в настройках магазина указан нужный единица измерения).
- Стоимость доставки не меняется: Проверьте приоритет хука — 10 обычно подходит, но если есть другие плагины, конфликтующие с этим фильтром, может понадобиться повысить приоритет, например, 20.
- Стоимость неправильная из-за кеширования: Очистите кеш WooCommerce и браузера, отключите кеширование страниц при тестировании.
Практические советы по безопасности и производительности
- Не используйте тяжелые вычисления внутри хука
woocommerce_package_rates, чтобы не замедлять загрузку страницы оформления заказа. - Если код усложняется, рассмотрите кеширование вычисленных значений с помощью Transient API для уменьшения нагрузки.
- Следите за обновлениями WooCommerce — иногда внутренние структуры
$packageмогут меняться, проверяйте совместимость кода.
Сравнение вариантов реализации
| Вариант | Преимущества | Недостатки |
|---|---|---|
Код через хук woocommerce_package_rates | Легкий, быстрый, гибкий, не требует доп. плагинов | Требует навыков PHP, ручная поддержка при изменениях требований |
| Платные плагины для расчета доставки | Готовый функционал, поддержка, GUI для настройки | Стоимость, нагрузка, избыточность функций |
| Использование зон доставки WooCommerce | Простота, встроенный функционал | Малая гибкость при сложных условиях |