Сценарий типичный: в корзине оказываются товары с разными классами доставки, а магазин должен либо показать их отдельными группами, либо не давать оформить заказ в одном чекауте без явного разделения. Чаще всего проблема всплывает после настройки тарифов доставки, подключения нескольких складов или когда часть ассортимента отправляется курьером, а часть — только самовывозом.
Если просто пытаться «спрятать» товары в интерфейсе корзины, можно получить побочные эффекты: неверный расчет доставки, дубли в итогах, ошибки при применении купонов и некорректные письма клиенту. Поэтому лучше решать задачу на уровне логики корзины, а не только верстки.
Когда это действительно нужно
Разделение корзины по классам доставки полезно, если у вас есть хотя бы один из этих сценариев:
- товары с разными способами отправки нельзя отправить одной посылкой;
- часть ассортимента должна оформляться отдельно из-за разных складов;
- доставка зависит не только от зоны, но и от типа товара;
- нужно явно показать клиенту, что в заказе есть несколько групп с разной логистикой;
- менеджеру важно видеть, какие позиции относятся к какому способу доставки.
Диагностика проблемы: что проверить до кода
Перед изменением логики корзины проверьте базовые настройки WooCommerce. Часто проблема не в теме и не в шаблоне, а в конфигурации доставки.
Проверьте классы доставки у товаров
Убедитесь, что у нужных товаров действительно назначены shipping class. Если класс не задан, фильтровать корзину по нему бессмысленно: товар попадет в «общую» группу.
Проверьте зоны и методы доставки
Если у вас несколько зон доставки, сначала убедитесь, что WooCommerce корректно считает тарифы без кастомного кода. Иначе вы будете лечить не ту проблему. Для теста добавьте в корзину по одному товару из каждой группы и посмотрите, как меняется блок доставки на чекауте.
Проверьте, не вмешивается ли плагин кэширования
Кэш корзины и мини-корзины иногда маскирует изменения. Если после правок вы не видите разницы, временно отключите оптимизацию фрагментов корзины и очистите кэш страницы оформления заказа.
Подходы к решению: плагин, код, компромисс
| Подход | Что дает | Минус |
|---|---|---|
| Плагин для логики доставки | Быстрее запуск, меньше кода | Может быть избыточным для простой задачи |
| Код в дочерней теме или мини-плагине | Полный контроль над корзиной и чекаутом | Нужно тестировать после обновлений WooCommerce |
| Компромисс: код только для валидации | Не ломает интерфейс, но ограничивает оформление | Пользователь увидит ошибку уже на чекауте |
Если задача точечная, я бы не начинал с тяжелого плагина. Для большинства магазинов достаточно небольшой проверки на этапе оформления заказа и понятного сообщения клиенту.
Пошаговое решение через код
Ниже пример, который не пытается физически «разрезать» корзину на две отдельные корзины, а проверяет состав заказа и запрещает оформление, если в корзине смешаны товары с разными классами доставки. Это безопаснее, чем вмешиваться в расчет totals и ломать купоны или налоги.
<?php
add_action( 'woocommerce_check_cart_items', 'wptemplates_validate_shipping_classes_in_cart' );
function wptemplates_validate_shipping_classes_in_cart() {
if ( ! WC()->cart || WC()->cart->is_empty() ) {
return;
}
$classes = array();
foreach ( WC()->cart->get_cart() as $cart_item ) {
if ( empty( $cart_item['data'] ) || ! is_object( $cart_item['data'] ) ) {
continue;
}
$product = $cart_item['data'];
$class_id = $product->get_shipping_class_id();
if ( $class_id ) {
$classes[ $class_id ] = true;
}
}
if ( count( $classes ) > 1 ) {
wc_add_notice(
'В корзине есть товары с разными классами доставки. Разделите заказ или оформите позиции отдельно.',
'error'
);
}
}
Этот вариант подходит, если бизнес-правило жесткое: смешивать товары нельзя. Если же нужно не запрещать заказ, а только группировать позиции для менеджера, логика будет другой.
Если нужно только пометить группы в корзине
Иногда достаточно вывести рядом с каждой позицией ее класс доставки. Это помогает менеджеру и клиенту понять, почему доставка считается отдельно, но не мешает оформлению.
<?php
add_filter( 'woocommerce_get_item_data', 'wptemplates_show_shipping_class_in_cart', 10, 2 );
function wptemplates_show_shipping_class_in_cart( $item_data, $cart_item ) {
if ( empty( $cart_item['data'] ) || ! is_object( $cart_item['data'] ) ) {
return $item_data;
}
$product = $cart_item['data'];
$class_id = $product->get_shipping_class_id();
if ( ! $class_id ) {
return $item_data;
}
$term = get_term( $class_id, 'product_shipping_class' );
if ( $term && ! is_wp_error( $term ) ) {
$item_data[] = array(
'name' => 'Класс доставки',
'value' => $term->name,
);
}
return $item_data;
}
Такой подход не меняет расчет корзины и обычно безопаснее для магазинов, где уже настроены купоны, налоги и несколько способов доставки.
Как проверить, что решение сработало
После внедрения проверьте не только визуальный результат, но и поведение checkout.
- Добавьте в корзину товары из одного класса доставки и убедитесь, что заказ проходит.
- Добавьте товар из другого класса и проверьте, появляется ли предупреждение или метка.
- Откройте страницу оформления заказа в режиме инкогнито, чтобы исключить влияние кэша и сохраненной сессии.
- Проверьте письма WooCommerce: в них должны корректно отображаться позиции и их названия.
- Если используете купоны, протестируйте применение скидки до и после изменения логики.
Для быстрой диагностики можно временно вывести в лог список классов доставки, которые попали в корзину. Это проще, чем гадать по интерфейсу.
<?php
add_action( 'woocommerce_check_cart_items', function() {
if ( ! WC()->cart ) {
return;
}
$classes = array();
foreach ( WC()->cart->get_cart() as $cart_item ) {
if ( ! empty( $cart_item['data'] ) ) {
$classes[] = $cart_item['data']->get_shipping_class_id();
}
}
error_log( 'Cart shipping classes: ' . implode( ',', array_filter( $classes ) ) );
} );
Частые ошибки и как их исправить
Проверяют не тот объект товара
В корзине нужно работать с объектом из $cart_item['data'], а не с ID товара напрямую. Иначе методы WooCommerce, включая get_shipping_class_id(), будут недоступны.
Считают, что вариация наследует класс автоматически
У вариативных товаров класс доставки может быть задан на уровне вариации или родительского товара, и это нужно проверить отдельно. Если логика строится на классе доставки, тестируйте именно вариации, а не только базовый товар.
Пытаются менять totals вручную
Если вмешиваться в сумму корзины через woocommerce_before_calculate_totals без четкой причины, легко сломать налоги, купоны и повторный расчет. Для задачи разделения по доставке это обычно лишнее.
Не очищают кэш и фрагменты корзины
После правок в логике доставки старые фрагменты мини-корзины могут показывать устаревшие данные. Очистите кэш страницы, объектный кэш и проверьте поведение без оптимизаторов JavaScript.
Практические советы по безопасности и производительности
Если решение идет в продакшн, лучше вынести код в мини-плагин или дочернюю тему, а не править файлы родительской темы. Так вы не потеряете изменения при обновлении.
Еще два момента, которые реально важны:
- не добавляйте тяжелые запросы к базе внутри цикла по товарам в корзине;
- не используйте логику, которая каждый раз дергает внешние API на странице checkout;
- проверяйте, как решение работает на мобильном чекауте, где ошибки валидации заметнее;
- если магазин большой, тестируйте на staging-копии с реальными типами товаров и купонами.
Если вам нужно не просто ограничить оформление, а построить более сложную логику доставки, иногда проще подключить специализированный плагин для shipping rules, чем поддерживать большой кастомный код. Но для узкой задачи с классами доставки код обычно быстрее, прозрачнее и легче отлаживается.