Проблема: необходимость динамического изменения цены при оформлении заказа
В WooCommerce иногда требуется изменить стоимость товаров в заказе не при добавлении в корзину, а непосредственно во время оформления заказа — например, применить скидку или наценку на основе условий оплаты, типа пользователя или других параметров. Стандартными средствами WooCommerce это сделать сложно, так как цены фиксируются при добавлении в корзину.
Диагностика проблемы: почему изменение стоимости не срабатывает
Если попытаться изменить цену товара напрямую в объекте WC_Cart после добавления в корзину, то изменения могут не сохраниться или не отобразиться на странице оформления заказа. Это связано с тем, что WooCommerce кеширует цены и рассчитывает итоговую сумму один раз, а потом не обновляет их при повторных изменениях.
Чтобы корректно изменить цену, нужно использовать специальные хуки и методы, которые WooCommerce предоставляет для динамического изменения стоимости товара в корзине и заказе.
Пошаговое решение: динамическое изменение стоимости товара на этапе оформления
Ниже приведён пример кода, который изменяет цену товара в корзине на 10% ниже при оформлении заказа, если выбран определённый способ оплаты (например, «Оплата при получении»).
add_action('woocommerce_before_calculate_totals', 'custom_dynamic_price_change', 20, 1);
function custom_dynamic_price_change( $cart ) {
if ( is_admin() && !defined('DOING_AJAX') ) return;
// Проверяем, что корзина не пуста
if ( did_action('woocommerce_before_calculate_totals') >= 2 ) return;
// Получаем выбранный метод оплаты из сессии
$chosen_payment_method = WC()->session->get('chosen_payment_method');
// Условие для изменения цены
if ( $chosen_payment_method === 'cod' ) { // cod - код способа оплаты «Оплата при получении»
foreach ( $cart->get_cart() as $cart_item_key => $cart_item ) {
$original_price = $cart_item['data']->get_regular_price();
$discounted_price = $original_price * 0.9; // скидка 10%
$cart_item['data']->set_price( $discounted_price );
}
} else {
// Восстанавливаем оригинальные цены, если условие не выполняется
foreach ( $cart->get_cart() as $cart_item_key => $cart_item ) {
$cart_item['data']->set_price( $cart_item['data']->get_regular_price() );
}
}
}
Код нужно добавить в файл functions.php вашей темы или в отдельный плагин.
Объяснение кода:
- Хук
woocommerce_before_calculate_totalsсрабатывает перед пересчётом итоговой стоимости корзины. - Проверяется выбранный метод оплаты, который сохраняется в сессии WooCommerce.
- Для каждого товара в корзине цена изменяется через метод
set_price(). - Если условие не выполняется, цены восстанавливаются до обычных.
Проверка результата после внедрения
- Добавьте товары в корзину.
- Перейдите на страницу оформления заказа (
/checkout/). - Выберите способ оплаты «Оплата при получении» (или тот, который вы указали в коде).
- Обратите внимание, что цены на товары изменятся — станут на 10% ниже.
- При выборе других способов оплаты цены вернутся к обычным.
Для проверки можно включить режим отладки WooCommerce или добавить в код error_log для вывода текущей цены.
Частые ошибки и как их исправить
- Изменения не применяются: Возможно, хук вызывается некорректно или
WC()->session->get('chosen_payment_method')возвращает пустое значение. Проверьте, выбран ли способ оплаты и доступна ли сессия на данном этапе. - Цены меняются в админке или в ненужных местах: Добавьте проверку
is_admin()и!defined('DOING_AJAX'), чтобы ограничить выполнение только фронтендом. - Цены сбрасываются после обновления страницы: Убедитесь, что код вызывается на каждом пересчёте корзины, а не только один раз.
- Конфликты с другими плагинами, изменяющими цены: Проверяйте приоритеты хуков и порядок загрузки плагинов.
Практические советы по безопасности и производительности
- Не храните изменённые цены в базе данных, меняйте их только в объекте корзины — это позволит избежать проблем с данными заказов и отчетами.
- Ограничивайте выполнение кода условиями типа проверки страницы и сессии, чтобы не замедлять загрузку других страниц сайта.
- Для сложных условий используйте кэширование данных и минимизируйте обращения к базе данных внутри цикла изменения цен.
Сравнение вариантов реализации изменения цены в WooCommerce
| Вариант | Описание | Плюсы | Минусы |
|---|---|---|---|
Изменение цены через woocommerce_before_calculate_totals | Динамическое изменение цены в корзине через хук | Гибко, без изменения базы, работает для любых условий | Нужно правильно настроить условия, возможны конфликты с другими плагинами |
| Создание отдельного плагина для скидок | Использование плагина с настройками скидок и наценок | Простой интерфейс, готовые решения | Может быть избыточным, влияет на производительность, не всегда подходит для кастомных условий |
| Манипуляция ценами в базе | Прямое изменение цен в базе данных продукта или заказа | Постоянный эффект | Риск потери данных, ошибки в отчетах, не рекомендуется |