Диагностика задачи: почему нужно менять цену по атрибуту
В магазинах на WooCommerce часто возникает необходимость динамически менять цену товара в зависимости от выбранных пользователем атрибутов или других условий (например, даты, ролей пользователя, наличия в корзине определённых товаров). Использование стандартных вариаций не всегда покрывает все бизнес-сценарии, особенно если требуется сложная логика или изменение цены до добавления в корзину.
Проблема: без кастомизации WooCommerce не позволяет гибко менять цену товара по условиям, заданным на лету. Часто администраторы пытаются решить это через плагины, которые слишком громоздки или не подходят под задачу.
Как программно изменить цену товара по атрибуту
Рассмотрим пример, как с помощью фильтра woocommerce_get_price изменить цену товара в зависимости от выбранного атрибута (например, цвет). Предположим, что если выбран атрибут цвет red, цена увеличивается на 10%. Для вариативного товара это можно сделать так:
add_filter('woocommerce_get_price', 'custom_dynamic_price_by_attribute', 10, 2);
function custom_dynamic_price_by_attribute($price, $product) {
if (!$product->is_type('variable')) {
return $price;
}
// Получаем текущий ID вариации из запроса
if (isset($_REQUEST['variation_id']) && $_REQUEST['variation_id']) {
$variation = wc_get_product(absint($_REQUEST['variation_id']));
if (!$variation) {
return $price;
}
// Получаем атрибуты вариации
$attributes = $variation->get_attributes();
// Проверяем атрибут 'pa_color' на значение 'red'
if (isset($attributes['pa_color']) && $attributes['pa_color'] === 'red') {
// Увеличиваем цену на 10%
$price = $price * 1.10;
}
}
return $price;
}Этот код срабатывает при получении цены товара и проверяет, есть ли выбранный вариант с атрибутом pa_color=red. При совпадении цена увеличивается на 10%.
Учет дополнительных условий для изменения цены
Можно добавить проверку, например, роли пользователя или текущей даты. Пример с проверкой роли:
add_filter('woocommerce_get_price', 'custom_price_by_attribute_and_role', 10, 2);
function custom_price_by_attribute_and_role($price, $product) {
if (!$product->is_type('variable')) {
return $price;
}
if (!current_user_can('premium_customer')) {
return $price;
}
if (isset($_REQUEST['variation_id']) && $_REQUEST['variation_id']) {
$variation = wc_get_product(absint($_REQUEST['variation_id']));
if (!$variation) {
return $price;
}
$attributes = $variation->get_attributes();
if (isset($attributes['pa_color']) && $attributes['pa_color'] === 'red') {
$price = $price * 0.9; // скидка 10% для премиум
}
}
return $price;
}Пошаговое решение: как внедрить и протестировать
- Откройте файл
functions.phpвашей дочерней темы или создайте небольшой плагин для кастомных функций. - Скопируйте и вставьте приведённый выше код с нужной логикой изменения цены.
- Проверьте, что у вас есть вариативный товар с атрибутом
pa_colorи значениемred. - Откройте страницу товара в браузере и выберите вариант с нужным атрибутом.
- Убедитесь, что цена изменилась согласно логике (увеличилась или уменьшилась).
- Для проверки роли пользователя - залогиньтесь под пользователем с ролью
premium_customerили добавьте эту роль через функции. - Очистите кэш сайта и браузера, если изменения не видны сразу.
Проверка результата после внедрения
Для проверки корректности работы:
- Перейдите на страницу вариативного товара.
- Выберите вариацию с атрибутом
pa_color=red. - Проверьте цену — она должна увеличиться на 10% (или изменить согласно другому коду).
- Смените атрибут на другой — цена должна вернуться к базовой.
- Если используется роль пользователя, проверьте цену под разными аккаунтами.
Частые ошибки и как их исправлять
- Цена не меняется: проверьте правильность названия атрибута (
pa_color— системное имя, не отображаемое в админке, а slug). Проверьте, что в URL передаетсяvariation_id. - Изменение цены некорректно срабатывает на простых товарах: добавьте проверку типа товара
$product->is_type('variable'). - Кэш мешает увидеть изменения: отключите кэширование страниц и плагинов на время тестирования.
- Роль пользователя не учитывается: убедитесь, что роль существует и пользователь правильно авторизован.
- Цена меняется, но не отображается в корзине/чекауте: для корректного изменения цены в корзине нужно использовать фильтр
woocommerce_before_calculate_totalsдля изменения цены вариации в объекте корзины.
Практические советы по производительности и безопасности
- Не используйте глобальные запросы или тяжелые операции в фильтрах цены — они вызываются часто.
- Избегайте изменения цены напрямую в базе — используйте фильтры WooCommerce.
- Для сложной логики лучше использовать серверные API и кэширование результатов.
- Проверяйте наличие и валидность данных
variation_id, чтобы избежать ошибок PHP.
Дополнительно: изменение цены в корзине для вариативных товаров
Чтобы изменить цену вариации в корзине согласно нашим условиям, добавьте следующий код:
add_action('woocommerce_before_calculate_totals', 'custom_change_cart_item_price', 20, 1);
function custom_change_cart_item_price($cart) {
if (is_admin() && !defined('DOING_AJAX')) {
return;
}
foreach ($cart->get_cart() as $cart_item_key => $cart_item) {
$product = $cart_item['data'];
if (!$product->is_type('variation')) {
continue;
}
$variation_attributes = $product->get_attributes();
if (isset($variation_attributes['pa_color']) && $variation_attributes['pa_color'] === 'red') {
$new_price = $product->get_regular_price() * 1.10; // +10%
$product->set_price($new_price);
}
}
}Этот код гарантирует, что цена в корзине будет соответствовать измененной цене на странице товара.