Диагностика задачи: зачем менять стоимость товара после оплаты
В стандартном WooCommerce цена товара фиксирована до оплаты и не меняется автоматически. Однако в ряде случаев требуется изменить стоимость товара после подтверждения оплаты заказа: например, для применения скидок при повторных покупках, корректировки цены на основе дополнительной информации или для реализации бонусных программ.
Основная проблема — как корректно и безопасно изменить цену товара после того, как заказ уже оформлен и оплачен, не нарушая логику WooCommerce и не создавая конфликтов с другими процессами.
Пошаговое решение: использование хука woocommerce_order_status_completed
WooCommerce предоставляет хук woocommerce_order_status_completed, который срабатывает, когда заказ переводится в статус «завершён» (обычно после оплаты). Это подходящее место для изменения цены товаров в заказе.
Пример кода для изменения цены товара в заказе после оплаты:
add_action('woocommerce_order_status_completed', 'change_product_price_after_payment', 10, 1);function change_product_price_after_payment($order_id) { $order = wc_get_order($order_id); if (!$order) { return; } foreach ($order->get_items() as $item_id => $item) { $product = $item->get_product(); if (!$product) { continue; } // Пример логики: если это определённый товар, меняем цену if ($product->get_id() === 123) { // ID товара $new_price = 500; // Новая цена в рублях // Меняем цену только для данного заказа (не глобально) $item->set_subtotal($new_price * $item->get_quantity()); $item->set_total($new_price * $item->get_quantity()); $item->save(); } } // Обновляем общую сумму заказа после изменения цен в товарах $order->calculate_totals();}Объяснение:
- Используется хук
woocommerce_order_status_completed— безопасный момент, когда заказ подтверждён. - Получаем объект заказа
$order. - Перебираем товары заказа, ищем нужный по ID или другому критерию.
- Для нужного товара меняем цену в заказе без изменения цены самого товара в каталоге.
- Пересчитываем итоги заказа методом
calculate_totals().
Особенности
Изменение цены в заказе не влияет на цену товара в магазине. Это важно, чтобы не ломать логику ценообразования для других покупателей.
Проверка результата после внедрения
Чтобы убедиться, что всё работает:
- Создайте тестовый заказ с товаром с ID 123.
- Оплатите заказ (можно в режиме теста или через шлюз «Оплата по счету»).
- Переведите заказ в статус «завершён» вручную или дождитесь автоматического обновления.
- Откройте детали заказа в админке — проверьте, изменилась ли цена товара в заказе на 500 рублей.
- Обратите внимание, что общая сумма заказа пересчиталась.
Частые ошибки и как их исправить
- Изменяется цена товара в каталоге: Используйте методы
set_subtotalиset_totalдля позиции заказа, а неupdate_post_metaпродукта. - Итоги заказа не пересчитываются: Не забудьте вызвать
$order->calculate_totals();после изменения цен. - Изменения не видны в админке: Проверьте, что хук подключён с правильным приоритетом и что ID товара совпадает с вашим тестовым товаром.
- Изменения влияют на другие заказы: Изменяйте цену только для позиций конкретного заказа, не меняйте глобальную цену продукта.
Практические советы по безопасности и производительности
- Проверяйте, что
$orderдействительно загружен — это поможет избежать ошибок PHP. - Не используйте тяжелые запросы внутри обработки — лучше ограничиться данными заказа.
- Если изменений много, кэшируйте результаты или используйте асинхронные задачи для обновления заказов.
- Для прозрачности логируйте изменения, чтобы потом можно было отследить, какие цены и когда были изменены.
Сравнение вариантов реализации
| Метод | Плюсы | Минусы | Когда использовать |
|---|---|---|---|
| Изменение цены в позиции заказа | Безопасно, не влияет на каталог, легко откатить | Цена меняется только в заказе, не глобально | Коррекция цены для конкретного заказа |
| Изменение цены товара глобально | Меняется цена для всех покупателей | Риск ошибок, влияет на другие заказы | Когда нужно обновить цену товара для всего магазина |
| Создание скидочного купона после оплаты | Простой способ дать бонусы без изменения цены | Не меняет стоимость уже оплаченного заказа | Для бонусных программ и акций |