Диагностика задачи: зачем менять стоимость товаров автоматически
В WooCommerce часто возникает необходимость динамически менять цену товаров в зависимости от условий: например, скидка для определённых ролей пользователей, изменение цены при покупке большого количества, или специальная наценка при определённых вариантах доставки. Если делать это вручную, сложно поддерживать актуальность цен и управлять акциями.
Основная сложность — корректно изменить цену товара именно для отображения в корзине и на странице товара, не ломая логику WooCommerce и не влияя на базовые данные в базе.
Как определить, что цена товара изменяется правильно
- Цена на странице товара и в каталоге должна отображать актуальное значение.
- В корзине и на странице оформления заказа должна быть применена та же цена.
- В админке в карточке товара базовая цена должна оставаться неизменной.
- В заказах должна сохраняться изменённая цена, чтобы корректно учесть итоговую стоимость.
Пошаговое решение: пример изменения цены для определённой роли пользователя
Ниже — рабочий пример, как изменить цену товаров для пользователей с ролью wholesale_customer. Это можно расширить для других условий.
add_filter('woocommerce_get_price', 'custom_dynamic_price', 10, 2);
add_filter('woocommerce_get_sale_price', 'custom_dynamic_price', 10, 2);
add_filter('woocommerce_get_price_html', 'custom_price_html', 10, 2);
function custom_dynamic_price($price, $product) {
if (is_admin()) return $price; // не изменяем в админке
if (!is_user_logged_in()) return $price;
$user = wp_get_current_user();
if (in_array('wholesale_customer', (array) $user->roles)) {
// уменьшаем цену на 20%
$new_price = $price * 0.8;
return $new_price;
}
return $price;
}
function custom_price_html($price_html, $product) {
if (is_admin()) return $price_html;
if (!is_user_logged_in()) return $price_html;
$user = wp_get_current_user();
if (in_array('wholesale_customer', (array) $user->roles)) {
$regular_price = wc_get_price_to_display($product, ['price' => $product->get_regular_price()]);
$discounted_price = wc_get_price_to_display($product, ['price' => $product->get_regular_price() * 0.8]);
if ($discounted_price < $regular_price) {
$price_html = wc_price($discounted_price) . ' <del>' . wc_price($regular_price) . '</del>';
}
}
return $price_html;
}Объяснение кода
Фильтры woocommerce_get_price и woocommerce_get_sale_price изменяют цену товара на лету. Фильтр woocommerce_get_price_html меняет отображение цены, показывая и скидочную, и обычную цену. Проверяется роль пользователя, чтобы применять скидку только для нужной группы.
Проверка результата после внедрения
- Залогиньтесь под пользователем с ролью
wholesale_customerи проверьте цену товара на странице каталога и в карточке товара. - Добавьте товар в корзину и убедитесь, что в корзине и на странице оформления заказа цена соответствует скидке.
- Залогиньтесь под обычным пользователем — цена должна быть без изменений.
- В админке в карточке товара цена не должна меняться.
Частые ошибки при автоматическом изменении цены
- Изменение цены в админке: если не поставить проверку
is_admin(), цена товара меняется и в панели управления, что ломает логику. - Неправильное отображение цен: без фильтра
woocommerce_get_price_htmlпользователь будет видеть только базовую цену, а в корзине другую — это сбивает с толку. - Неучёт разных типов товаров: переменные, групповые или внешние товары требуют отдельной логики обработки.
- Необработанные случаи для незарегистрированных пользователей: если условие не проверяется, цена может меняться неправильно.
Практические советы по безопасности и производительности
- Используйте кэширование для снижения нагрузки, особенно если вычисление цены зависит от сложных условий.
- Не храните изменённые цены в базе, изменяйте их на лету через хуки WooCommerce.
- Проверяйте корректность ролей и прав пользователей, чтобы избежать неправильного предоставления скидок.
- Тестируйте изменения на тестовом стенде перед внесением на живой сайт.
Сравнение вариантов решения задачи
| Метод | Плюсы | Минусы | Применимость |
|---|---|---|---|
| Изменение цены через хуки WooCommerce (как в статье) | Не меняет базу, гибко, быстро | Требует понимания API, сложнее для новичков | Лучше всего для динамических скидок и цен по ролям |
| Использование плагинов для скидок и динамических цен | Готовое решение, минимум кода | Может быть тяжёлым, ограниченные настройки, платные | Для быстрых решений без кастомной логики |
| Изменение цен в базе напрямую | Простота для простых случаев | Риск сломать логику, не отражает динамические условия | Редко рекомендуется, только для одноразовых правок |