Диагностика задачи: когда нужна автоматическая корректировка цены заказа
В стандартном WooCommerce цены товаров фиксированы и меняются вручную через админку или массовыми правками. Однако часто возникает задача динамически изменять цену товара при обновлении заказа — например, применять скидку, добавлять наценку или менять цену в зависимости от статуса заказа или других условий.
Типичные сценарии:
- Изменение цены товара по промокоду после оформления заказа
- Применение скидки на дополнительные товары при апдейте заказа
- Корректировка цены в зависимости от времени обработки заказа
Без кастомного кода WooCommerce не поддерживает такие изменения автоматически, что приводит к необходимости ручной правки или использования сторонних плагинов.
Как отследить обновление заказа и изменить цены товаров
Для решения задачи нужно использовать хук woocommerce_before_calculate_totals, который вызывается при пересчёте корзины и заказа. Обновлять цену товара в заказе нужно именно через объекты WC_Order_Item_Product.
Пример кода, который применяет скидку 10% ко всем товарам, если заказ обновляется и статус — «обрабатывается»:
add_action('woocommerce_before_calculate_totals', 'custom_modify_order_item_prices', 10, 1);
function custom_modify_order_item_prices($cart) {
if (is_admin() && !defined('DOING_AJAX')) return;
// Проверяем, что объект корзины
if (did_action('woocommerce_before_calculate_totals') >= 2) return;
foreach ($cart->get_cart() as $cart_item_key => $cart_item) {
$product = $cart_item['data'];
$original_price = $product->get_regular_price();
// Пример логики: скидка 10% при обновлении заказа
$new_price = $original_price * 0.9;
$product->set_price($new_price);
}
}Для изменения цены товаров непосредственно в заказе (после оформления) нужно работать с объектом заказа, например, по событию woocommerce_order_edit_status или woocommerce_order_status_changed:
add_action('woocommerce_order_status_changed', 'custom_update_order_item_prices', 10, 4);
function custom_update_order_item_prices($order_id, $old_status, $new_status, $order) {
if ($new_status !== 'processing') return; // ограничиваем по статусу
foreach ($order->get_items() as $item_id => $item) {
$product = $item->get_product();
$original_price = $product->get_regular_price();
$new_price = $original_price * 0.9; // скидка 10%
$item->set_subtotal($new_price * $item->get_quantity());
$item->set_total($new_price * $item->get_quantity());
$item->save();
}
$order->calculate_totals();
$order->save();
}Пошаговое решение: как внедрить и проверить корректировку цены
- Добавьте один из приведённых выше фрагментов кода в файл темы
functions.phpили в собственный плагин. - Обновите корзину или измените статус заказа (в зависимости от выбранного хука).
- Перейдите в админку WooCommerce → Заказы и откройте изменённый заказ.
- Проверьте цены товаров и итоговую сумму — они должны измениться согласно логике скрипта.
- Если работает с корзиной — проверьте цену товара непосредственно в клиентской части сайта, обновив корзину.
Как проверить, что цена изменилась
- В админке откройте заказ и посмотрите цены в блоке товаров — они должны соответствовать новым значениям.
- Проверьте итоговую сумму заказа — она должна пересчитаться автоматически.
- В корзине при использовании
woocommerce_before_calculate_totals— убедитесь, что цены отображаются с учётом скидки. - Для отладки можно добавить
error_logвнутри функций, чтобы убедиться, что они вызываются.
Частые ошибки и как их исправить
- Изменение цены товара не влияет на итог заказа. Причина: не вызван
$order->calculate_totals()и$order->save()после изменения цен в заказе. Решение: добавьте эти вызовы. - Цена меняется, но только в админке, а не на сайте. Причина: изменение происходит только в объекте
WC_Order_Item_Productбез обновления корзины. Решение: для фронтенда используйтеwoocommerce_before_calculate_totals. - Цены меняются несколько раз подряд. Причина: хук вызывается многократно без проверки. Решение: добавьте проверку с помощью
did_action. - Изменения не сохраняются. Причина: не вызван метод
save()у объекта заказа или элементов.
Практические советы по безопасности и производительности
- Не изменяйте цены в цикле без ограничений — используйте проверки статуса заказа или условия для минимизации нагрузки.
- Для масштабируемости лучше инкапсулировать логику в отдельный класс.
- Всегда тестируйте изменения на тестовой среде, чтобы избежать потери данных или ошибок при оплате.
- Используйте transient или метаданные заказа для хранения информации о применённых скидках, чтобы избежать повторных изменений.
Сравнение способов реализации автоматической корректировки цены
| Метод | Где применяется | Плюсы | Минусы |
|---|---|---|---|
Хук woocommerce_before_calculate_totals | Корзина, оформление заказа | Изменяет цену до оформления | Не изменяет уже оформленные заказы |
Хук woocommerce_order_status_changed | Редактирование заказов после оформления | Меняет цену в заказе, учитывается в оплате | Не влияет на корзину, требует пересчёта заказа |
| Плагины динамического ценообразования | Готовые решения | Много функций, удобный интерфейс | Могут быть тяжелыми и дорогими |