Интеграция службы доставки в WooCommerce
WooCommerce из коробки предлагает три метода доставки: flat rate, free shipping и local pickup. Для реальной логистики этого недостаточно — нужны тарифы конкретного перевозчика, расчёт стоимости по габаритам и весу, трекинг-номера в личном кабинете покупателя.
Как WooCommerce работает с доставкой
Архитектура доставки строится на трёх слоях:
- Shipping zones — географические зоны (страна, регион, почтовый индекс)
-
Shipping methods — методы внутри зоны, каждый реализует
WC_Shipping_Method - Shipping rates — тарифы, которые метод возвращает при расчёте корзины
Кастомный метод доставки — это класс, расширяющий WC_Shipping_Method:
class My_Courier_Shipping_Method extends WC_Shipping_Method {
public function __construct( $instance_id = 0 ) {
$this->id = 'my_courier';
$this->instance_id = absint( $instance_id );
$this->method_title = 'MyCourier';
$this->method_description = 'Доставка через MyCourier API';
$this->supports = [ 'shipping-zones', 'instance-settings' ];
$this->init();
}
public function init(): void {
$this->init_form_fields();
$this->init_settings();
$this->api_key = $this->get_option( 'api_key' );
add_action( 'woocommerce_update_options_shipping_' . $this->id, [ $this, 'process_admin_options' ] );
}
public function calculate_shipping( $package = [] ): void {
$rate = $this->get_rate_from_api( $package );
if ( $rate ) {
$this->add_rate([
'id' => $this->id . '_standard',
'label' => 'Стандартная доставка (' . $rate['days'] . ' дн.)',
'cost' => $rate['price'],
'meta_data' => [ 'courier_id' => $rate['service_id'] ],
]);
}
}
}
Метод регистрируется через фильтр:
add_filter( 'woocommerce_shipping_methods', function( $methods ) {
$methods['my_courier'] = My_Courier_Shipping_Method::class;
return $methods;
});
Расчёт тарифов через API перевозчика
Большинство российских и международных служб доставки имеют REST API для расчёта стоимости. Пример запроса к условному API:
private function get_rate_from_api( array $package ): ?array {
$weight = 0;
$dimensions = [ 'length' => 0, 'width' => 0, 'height' => 0 ];
foreach ( $package['contents'] as $item ) {
$product = $item['data'];
$qty = $item['quantity'];
$weight += (float) $product->get_weight() * $qty;
// Для объёма — max из габаритов товаров в заказе
}
$destination = $package['destination'];
$response = wp_remote_post( 'https://api.mycourier.ru/v2/calculate', [
'timeout' => 10,
'headers' => [
'Authorization' => 'Bearer ' . $this->api_key,
'Content-Type' => 'application/json',
],
'body' => wp_json_encode([
'from_city' => get_option( 'woocommerce_store_city' ),
'to_city' => $destination['city'],
'to_postcode' => $destination['postcode'],
'weight' => max( 0.1, $weight ),
'declared_value' => WC()->cart->get_cart_contents_total(),
]),
]);
if ( is_wp_error( $response ) || wp_remote_retrieve_response_code( $response ) !== 200 ) {
return null;
}
return json_decode( wp_remote_retrieve_body( $response ), true );
}
Результат кешируется транзиентом на 30–60 минут, чтобы не генерировать запрос на каждое изменение корзины:
$cache_key = 'courier_rate_' . md5( serialize( $package ) );
$cached = get_transient( $cache_key );
if ( $cached !== false ) {
$this->add_rate( $cached );
return;
}
// ... запрос к API ...
set_transient( $cache_key, $rate_data, 30 * MINUTE_IN_SECONDS );
Передача заказа в службу доставки
После подтверждения заказа нужно создать отправление в системе перевозчика. Хук woocommerce_order_status_processing срабатывает при переходе заказа в статус «В обработке»:
add_action( 'woocommerce_order_status_processing', function( int $order_id ) {
$order = wc_get_order( $order_id );
// Проверяем, что выбран наш метод доставки
foreach ( $order->get_shipping_methods() as $shipping_item ) {
if ( strpos( $shipping_item->get_method_id(), 'my_courier' ) === false ) {
continue;
}
$result = courier_create_shipment( $order );
if ( $result['tracking_number'] ) {
$order->update_meta_data( '_courier_tracking_number', $result['tracking_number'] );
$order->update_meta_data( '_courier_shipment_id', $result['shipment_id'] );
$order->save();
// Уведомляем покупателя
$order->add_order_note(
'Отправление создано. Трекинг: ' . $result['tracking_number'],
true // notify customer
);
}
}
});
Трекинг-номер в личном кабинете
Стандартный WooCommerce не показывает трекинг-номер. Добавляем его в письмо с подтверждением заказа и в страницу заказа:
// В письмах
add_action( 'woocommerce_email_order_meta', function( $order, $sent_to_admin ) {
$tracking = $order->get_meta( '_courier_tracking_number' );
if ( $tracking ) {
echo '<p><strong>Трекинг-номер:</strong> ' . esc_html( $tracking ) . '</p>';
echo '<p><a href="https://mycourier.ru/track/' . esc_attr( $tracking ) . '">Отследить посылку</a></p>';
}
}, 10, 2 );
// На странице заказа в личном кабинете
add_action( 'woocommerce_view_order', function( int $order_id ) {
$order = wc_get_order( $order_id );
$tracking = $order->get_meta( '_courier_tracking_number' );
if ( $tracking ) {
echo '<p class="tracking-info">Трекинг-номер: <strong>' . esc_html( $tracking ) . '</strong></p>';
}
});
Виджет карты для ПВЗ
Многие перевозчики предоставляют JavaScript-виджет для выбора пункта выдачи. Он встраивается на страницу оформления заказа:
// Добавляем поле для выбора ПВЗ в форму checkout
add_action( 'woocommerce_after_shipping_rate', function( $method ) {
if ( strpos( $method->id, 'my_courier_pickup' ) !== false ) {
echo '<div id="pvz-selector" style="display:none;"></div>';
echo '<input type="hidden" name="selected_pvz_id" id="selected_pvz_id">';
}
}, 10, 1 );
// resources/js/courier-pvz.js
jQuery(document).on('change', 'input[name="shipping_method[0]"]', function () {
if (this.value.includes('pickup')) {
initPvzWidget({
container: '#pvz-selector',
apiKey: window.courierConfig.apiKey,
city: jQuery('#billing_city').val(),
onSelect: (pvz) => {
jQuery('#selected_pvz_id').val(pvz.id);
jQuery('#pvz-selector').after(
`<p class="pvz-address">ПВЗ: ${pvz.address}</p>`
);
}
});
jQuery('#pvz-selector').show();
}
});
Автоматическое обновление статуса
Webhook от перевозчика или периодический cron-опрос обновляет статус заказа:
// wp-cron каждые 2 часа
add_action( 'courier_sync_tracking', function() {
$orders = wc_get_orders([
'meta_key' => '_courier_tracking_number',
'meta_compare' => 'EXISTS',
'status' => [ 'wc-processing', 'wc-shipped' ],
'limit' => 50,
]);
foreach ( $orders as $order ) {
$tracking = $order->get_meta( '_courier_tracking_number' );
$status = courier_api_get_status( $tracking );
if ( $status === 'delivered' && $order->get_status() !== 'completed' ) {
$order->update_status( 'completed', 'Доставлено по данным перевозчика.' );
}
}
});
if ( ! wp_next_scheduled( 'courier_sync_tracking' ) ) {
wp_schedule_event( time(), 'twohourly', 'courier_sync_tracking' );
}
Сроки реализации
Интеграция с одним перевозчиком через готовый плагин (СДЭК, DHL, Nova Poshta): 1–2 дня. Кастомный метод с полным циклом — расчёт, создание отправления, трекинг, webhook: 3–5 дней. Добавление виджета ПВЗ + кастомизация писем: плюс 1–2 дня. Интеграция нескольких перевозчиков с единым интерфейсом управления: 1–2 недели.







