Почему стандартное поведение WooCommerce не всегда удобно
В WooCommerce вариации товаров обычно имеют фиксированные цены, которые задаются вручную при создании вариаций. Однако часто возникает необходимость динамически менять стоимость товара в зависимости от выбранных атрибутов (например, добавлять стоимость за размер, материал или дополнительные опции). По умолчанию WooCommerce не предоставляет такого функционала, и пользователю приходится либо создавать множество вариаций с разными ценами, либо использовать сложные плагины.
Диагностика задачи: что именно нужно реализовать
Цель — автоматически изменять цену товара на странице товара в зависимости от выбранных пользователем атрибутов без создания множества вариаций. Так, если пользователь выбрал, например, размер "XL" или материал "капрон", цена должна автоматически пересчитываться и отображаться без перезагрузки страницы.
Основные требования
- Изменение цены должно происходить на клиенте (в браузере) при выборе атрибутов.
- Не создавать сотни вариаций для каждой комбинации.
- Возможность задать правила для изменения цены (например, +500 руб. за размер XL).
- Поддержка стандартного оформления заказа WooCommerce.
Пошаговое решение: реализация динамического изменения цены
1. Добавляем пользовательские цены для атрибутов через метаполя
Для хранения дополнительных цен к атрибутам рекомендуем использовать метаполя таксономии атрибутов. Например, для каждого термина атрибута (например, "XL") добавим метаполе additional_price с числом, которое будет прибавляться к базовой цене товара.
Добавить метаполе можно вручную через плагин Advanced Custom Fields (ACF) или программно:
function add_additional_price_field_to_attribute_term() {
// Добавляем поле в админке таксономии атрибутов
add_action('pa_size_edit_form_fields', 'edit_size_additional_price_field');
}
function edit_size_additional_price_field($term) {
$value = get_term_meta($term->term_id, 'additional_price', true);
?>
<tr class="form-field">
<th scope="row" valign="top"><label for="additional_price">Дополнительная цена</label></th>
<td>
<input type="number" name="additional_price" id="additional_price" value="<?php echo esc_attr($value); ?>" step="0.01" min="0" /> руб.
<p class="description">Цена, которая будет добавлена при выборе этого атрибута</p>
</td>
</tr>
<?php
}
add_additional_price_field_to_attribute_term();
// Сохраняем метаполе
function save_additional_price_field($term_id) {
if (isset($_POST['additional_price'])) {
update_term_meta($term_id, 'additional_price', floatval($_POST['additional_price']));
}
}
add_action('edited_pa_size', 'save_additional_price_field');
add_action('created_pa_size', 'save_additional_price_field');
2. Загружаем дополнительные цены для атрибутов на страницу товара
В шаблон страницы товара нужно вывести javascript с данными о дополнительных ценах, чтобы скрипт мог динамически пересчитывать цену.
add_action('wp_footer', 'enqueue_attribute_prices_script');
function enqueue_attribute_prices_script() {
if (!is_product()) return;
global $product;
if (!$product->is_type('variable')) return;
$attributes = $product->get_variation_attributes();
$data = [];
foreach ($attributes as $taxonomy => $terms) {
foreach ($terms as $term_slug) {
$term = get_term_by('slug', $term_slug, $taxonomy);
$additional_price = floatval(get_term_meta($term->term_id, 'additional_price', true));
$data[$taxonomy][$term_slug] = $additional_price;
}
}
?>
<script type="text/javascript">
var attributeAdditionalPrices = <?php echo json_encode($data); ?>;
</script>
<?php
}
3. Скрипт для динамического пересчёта и вывода цены
Добавим javascript, который будет слушать выбор атрибутов, суммировать дополнительную цену и изменять отображаемую цену товара на странице без перезагрузки.
jQuery(document).ready(function($) {
var basePrice = parseFloat($('.single_variation .price .woocommerce-Price-amount').first().text().replace(/[^0-9\.,]/g, '').replace(',', '.')) || 0;
function updatePrice() {
var totalAdditional = 0;
$('.variations select').each(function() {
var taxonomy = $(this).attr('name').replace('attribute_', '');
var val = $(this).val();
if (val && attributeAdditionalPrices[taxonomy] && attributeAdditionalPrices[taxonomy][val]) {
totalAdditional += parseFloat(attributeAdditionalPrices[taxonomy][val]);
}
});
var newPrice = basePrice + totalAdditional;
$('.single_variation .price .woocommerce-Price-amount').text(newPrice.toFixed(2) + ' ₽');
}
$('.variations select').on('change', function() {
updatePrice();
});
updatePrice();
});
Как проверить, что всё работает
- Перейдите на страницу вариативного товара.
- Задайте метаполя
additional_priceу терминов атрибутов, например, +500 руб. для "XL". - Выберите разные значения атрибутов в выпадающих списках.
- Обратите внимание на цену товара — она должна изменяться, прибавляя стоимость выбранных атрибутов.
- Добавьте товар в корзину и проверьте итоговую цену в корзине и заказе (для этого нужно дополнительно реализовать корректное изменение цены вариации через хуки WooCommerce, если требуется).
Частые ошибки и способы их исправления
- Цена не меняется при выборе атрибута: Проверьте, что данные
attributeAdditionalPricesкорректно передаются в JS (откройте консоль браузера). - Цена отображается некорректно (NaN или 0): Убедитесь, что в метаполях указаны числовые значения, а парсинг цены базового товара работает правильно. В разных темах верстка цены может отличаться.
- Цена меняется на странице, но не в корзине: Для корректного изменения цены в корзине нужно использовать PHP-хуки, например
woocommerce_before_calculate_totals, чтобы применить дополнительную стоимость к объекту товара в корзине. - Проблемы с кэшированием: Если на сайте включено кэширование (например, кеш на уровне сервера или плагин кэширования), убедитесь, что скрипты не кешируются и данные обновляются корректно.
Расширение: корректное применение дополнительной цены в корзине через PHP
Чистого изменения цены на фронте недостаточно. Чтобы итоговая сумма заказа учитывала дополнительные опции, применим фильтр woocommerce_before_calculate_totals:
add_action('woocommerce_before_calculate_totals', 'apply_additional_price_to_cart_item', 20, 1);
function apply_additional_price_to_cart_item($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('variable')) {
$additional = 0;
$variation_attributes = $cart_item['variation'];
foreach ($variation_attributes as $attr_name => $attr_value) {
$taxonomy = str_replace('attribute_', '', $attr_name);
$term = get_term_by('slug', $attr_value, $taxonomy);
if ($term) {
$price = floatval(get_term_meta($term->term_id, 'additional_price', true));
$additional += $price;
}
}
if ($additional > 0) {
$new_price = $product->get_price() + $additional;
$product->set_price($new_price);
}
}
}
}
Чек-лист для успешной настройки динамической цены
- Добавлены метаполя
additional_priceу терминов атрибутов. - Передаются данные дополнительных цен в javascript на странице товара.
- Написан и подключен скрипт, который динамически меняет цену на клиенте.
- Хук
woocommerce_before_calculate_totalsкорректно применяет дополнительную цену в корзине. - Тестирование на разных товарах и атрибутах прошло успешно.
- Проверено, что цены отображаются правильно в админке и в заказах.
Таблица сравнения решений для динамического изменения цены в WooCommerce
| Способ | Описание | Плюсы | Минусы |
|---|---|---|---|
| Создание вариаций с разными ценами | Создавать каждую комбинацию с нужной ценой вручную | Стандартный функционал WooCommerce, совместимость гарантирована | Сложно масштабировать, большое количество вариаций |
| Плагины динамического ценообразования | Использование готовых плагинов для настройки правил изменения цены | Удобство, много готовых функций | Могут быть дорогими, нагрузка на сайт, избыточность |
| Собственный код (описанный в статье) | Добавление дополнительной цены через метаполя и изменение цены на клиенте и сервере | Гибкость, контроль, нет зависимости от плагинов | Требует навыков программирования, нужно тестировать |