Диагностика задачи: зачем менять цену товара при оплате
Иногда в WooCommerce требуется динамически менять стоимость товаров в момент оформления или после успешной оплаты. Это может быть актуально для сложных акций, скидок, наложенных по определённым правилам, или корректировок цены в зависимости от способа оплаты.
Стандартные возможности WooCommerce не позволяют изменять цену товара в заказе после его создания, особенно если речь идёт о ценах, зависящих от статуса оплаты. Для реализации такой логики потребуется вмешательство в процесс обработки заказа через хуки.
Пошаговое решение: изменение цены товаров при оплате
1. Используем хук для перезаписи цены в корзине
Чтобы изменить цену товара до оформления заказа, можно использовать фильтр woocommerce_before_calculate_totals. Вот пример кода, меняющего цену товара на 90% от исходной, если выбрана оплата определённым способом:
add_action('woocommerce_before_calculate_totals', 'custom_discount_based_on_payment_method', 10, 1);
function custom_discount_based_on_payment_method($cart) {
if (is_admin() && !defined('DOING_AJAX')) return;
// Проверяем выбранный метод оплаты
$chosen_payment = WC()->session->get('chosen_payment_method');
if ($chosen_payment !== 'cod') return; // только для наложенного платежа
foreach ($cart->get_cart() as $cart_item_key => $cart_item) {
$original_price = $cart_item['data']->get_price();
$new_price = $original_price * 0.9; // 10% скидка
$cart_item['data']->set_price($new_price);
}
}2. Изменение цены уже в заказе после оплаты
Если нужно изменить цену товаров после успешной оплаты, например, для корректировки стоимости в заказе, стоит использовать хук woocommerce_order_status_completed. В этом примере уменьшим цену каждого товара в заказе на 5%:
add_action('woocommerce_order_status_completed', 'custom_update_order_item_prices_after_payment', 10, 1);
function custom_update_order_item_prices_after_payment($order_id) {
$order = wc_get_order($order_id);
foreach ($order->get_items() as $item_id => $item) {
$original_total = $item->get_total();
$new_total = $original_total * 0.95; // снижение на 5%
$item->set_total($new_total);
$item->save();
}
$order->calculate_totals();
$order->save();
}Как проверить, что изменение цены сработало
- Для первого варианта (в корзине) добавьте в корзину товар, выберите нужный способ оплаты и убедитесь, что цена товара изменилась в сумме заказа.
- Для второго варианта оформите заказ, дождитесь смены статуса на «завершён» и проверьте детали заказа в админке — должна быть изменена цена товаров и итоговая сумма.
Частые ошибки и способы исправления
- Изменения цены не применяются в корзине: Проверьте, что фильтр подключён именно к
woocommerce_before_calculate_totals, а не к хукам, которые вызываются слишком рано или поздно. - Цена в заказе не обновляется после оплаты: Убедитесь, что используете правильный хук статуса (
woocommerce_order_status_completedилиwoocommerce_payment_complete). - Изменённая цена не сохраняется: Не забывайте вызывать методы
save()для каждого элемента заказа иcalculate_totals()для всего заказа. - Влияние на налоги и купоны: Проверьте как изменение цены влияет на налоговые расчёты и скидки, при необходимости дорабатывайте логику.
Практические советы по производительности и безопасности
- Избегайте частых изменений цен в циклах, которые вызываются многократно, например, в
woocommerce_before_calculate_totals, без проверки условий. - Кэшируйте результаты вычислений цены, если операции сложные.
- Проверяйте наличие сессии и выбранного метода оплаты, чтобы не вызывать ошибки при прямом доступе к корзине по API.
- Не изменяйте цены напрямую в базе для заказов — используйте методы WooCommerce для корректного сохранения и пересчёта.
Сравнение способов изменения цены: фильтр корзины vs изменение после оплаты
| Метод | Когда применяется | Преимущества | Недостатки |
|---|---|---|---|
| woocommerce_before_calculate_totals | В процессе формирования корзины перед оформлением заказа | Цены видны пользователю сразу, влияет на итоговую сумму заказа | Нельзя менять цены уже созданных заказов; требует сессии |
| woocommerce_order_status_completed | После успешного завершения оплаты (статус заказа) | Можно изменять цену в заказах, гибко настраивать логику после оплаты | Пользователь видит цену до оплаты, возможны рассогласования |