Способ доставки
Способ доставки — класс, наследующий WC_Shipping_Method. Его главный метод calculate_shipping() получает содержимое корзины с адресом и сообщает цену. Способы привязаны к зонам доставки: зона — набор стран или регионов со своим списком способов и цен.
Зоны в панели
Откройте «WooCommerce → Настройки → Доставка». Создайте зону «Германия» с регионом «Германия» — в неё мы добавим свой способ. Покупателю показываются способы той зоны, под которую подходит его адрес.
Класс способа
Создайте файл includes/class-acme-shipping.php:
// wp-content/plugins/acme-shop/includes/class-acme-shipping.php
class Acme_Shipping extends WC_Shipping_Method
{
public function __construct($instanceId = 0)
{
$this->id = 'acme_courier';
$this->instance_id = absint($instanceId);
$this->method_title = 'Курьер Acme';
$this->method_description = 'Доставка собственным курьером.';
$this->supports = ['shipping-zones', 'instance-settings'];
$this->instance_form_fields = [
'title' => ['title' => 'Название', 'type' => 'text', 'default' => 'Курьер'],
'cost' => ['title' => 'Стоимость', 'type' => 'price', 'default' => '5'],
];
$this->title = $this->get_option('title');
}
public function calculate_shipping($package = []): void
{
$this->add_rate([
'id' => $this->get_rate_id(),
'label' => $this->title,
'cost' => (float) $this->get_option('cost'),
]);
}
}Экземпляр — способ, добавленный в конкретную зону: у каждого свой номер и свои настройки из instance_form_fields. Метод add_rate() предлагает покупателю вариант с названием и ценой.
Регистрация
// wp-content/plugins/acme-shop/acme-shop.php
add_action('woocommerce_shipping_init', function () {
require_once __DIR__ . '/includes/class-acme-shipping.php';
});
add_filter('woocommerce_shipping_methods', function (array $methods): array {
$methods['acme_courier'] = 'Acme_Shipping';
return $methods;
});Класс подключается на хуке woocommerce_shipping_init — раньше базового класса ещё нет. Ключ массива совпадает с id способа. Теперь откройте зону «Германия», нажмите «Добавить способ доставки» и выберите «Курьер Acme». На странице корзины с немецким адресом появится вариант «Курьер — 5,00 €».
Расчёт по содержимому
Аргумент $package содержит товары и адрес. Посчитаем цену по весу:
// wp-content/plugins/acme-shop/includes/class-acme-shipping.php
public function calculate_shipping($package = []): void
{
$weight = 0.0;
foreach ($package['contents'] as $item) {
$weight += (float) $item['data']->get_weight() * $item['quantity'];
}
$cost = (float) $this->get_option('cost') + max(0, $weight - 2) * 1.5;
$this->add_rate([
'id' => $this->get_rate_id(),
'label' => $this->title,
'cost' => $cost,
]);
}До двух килограммов действует базовая цена, каждый следующий килограмм добавляет 1,50 €. Вес товара задают в редакторе на вкладке «Доставка».
Ключ $package | Что в нём |
|---|---|
contents | Позиции корзины, как в WC()->cart->get_cart() |
contents_cost | Сумма товаров |
destination | Адрес: country, state, postcode, city |
Если способ недоступен — например, для слишком тяжёлой посылки, — add_rate() просто не вызывают.
Изменить чужие цены
Стоимость любых способов меняют фильтром, без своего класса. Сделаем доставку бесплатной от 50 €:
// wp-content/plugins/acme-shop/includes/cart.php
add_filter('woocommerce_package_rates', function (array $rates, array $package): array {
if ($package['contents_cost'] >= 50) {
foreach ($rates as $rate) {
$rate->set_cost(0);
}
}
return $rates;
}, 10, 2);Фильтр получает все варианты, найденные для посылки. Наберите корзину на 50 € — все способы доставки станут бесплатными. Фильтр работает и в блочной корзине.
Частая ошибка
Цену изменили в коде, а в корзине остаётся старая. WooCommerce запоминает варианты доставки в сессии покупателя и пересчитывает их, только когда изменились корзина или адрес. При отладке измените количество товара в корзине или включите «Режим отладки» в «WooCommerce → Настройки → Доставка → Параметры доставки» — он отключает это запоминание.