Товар в подарок Woocommerce

Давайте сделаем товар в подарок по купону. Добавьте сниппет-код:

/*
Plugin Name: Товар в подарок
Description: По купону товар в подарок
Version: 1.0.0
Author: avs-alexandra
Author URI: https://github.com/avs-alexandra
*/

/* ----------------------------------------
 * 1. Добавляем тип купона
 * ---------------------------------------- */
add_filter('woocommerce_coupon_discount_types', function($types) {
    $types['free_gift'] = 'Товар в подарок';
    return $types;
});

/* ----------------------------------------
 * 2. Поле выбора подарка в настройках купона
 * ---------------------------------------- */
add_action('woocommerce_coupon_options_usage_restriction', function($coupon_id, $coupon) {

    if (!is_object($coupon) || is_wp_error($coupon)) return;
    if (!method_exists($coupon, 'is_type') || !$coupon->is_type('free_gift')) return;

    $product_id = intval($coupon->get_meta('product_gift_single', true));
    ?>

    <div class="options_group">
        <p class="form-field">
            <label>Товар в подарок</label>

            <span style="display:flex; align-items:center; gap:6px;">

                <select class="wc-product-search"
                        style="width:260px;"
                        name="product_gift_single"
                        data-placeholder="Выберите товар…"
                        data-action="woocommerce_json_search_products_and_variations">

                    <option value=""></option>

                    <?php if ($product_id):
                        $p = wc_get_product($product_id);
                        if ($p): ?>
                            <option value="<?php echo esc_attr($product_id); ?>" selected>
                                <?php echo esc_html(wp_strip_all_tags($p->get_formatted_name())); ?>
                            </option>
                        <?php endif;
                    endif; ?>
                </select>

                <button type="button"
                        class="button"
                        id="clear-gift-product"
                        style="line-height:1; padding:0 6px 2px;">
                    
                </button>

            </span>

            <script>
                jQuery(function($){
                    $('#clear-gift-product').on('click', function(){
                        let $sel = $('select[name="product_gift_single"]');
                        $sel.val('').trigger('change');
                    });
                });
            </script>

        </p>
    </div>

    <?php
}, 10, 2);

/* ----------------------------------------
 * 3. Сохранение выбранного товара
 * ---------------------------------------- */
add_action('woocommerce_coupon_options_save', function($coupon_id, $coupon) {

    if (!is_object($coupon) || is_wp_error($coupon)) return;

    $product_id = isset($_POST['product_gift_single']) ? intval($_POST['product_gift_single']) : 0;

    if (!$product_id) {
        $coupon->update_meta_data('product_gift_single', '');
    } else {
        $coupon->update_meta_data('product_gift_single', $product_id);
    }

    $coupon->save();
}, 10, 2);

/* ----------------------------------------
 * 4. Добавляем подарок при применении купона
 * ---------------------------------------- */
add_action('woocommerce_applied_coupon', function($coupon_code) {

    if ( empty($coupon_code) ) return;

    $coupon = new WC_Coupon( $coupon_code );
    if ( is_wp_error($coupon) || ! is_object($coupon) ) return;
    if ( ! $coupon->is_type('free_gift') ) return;

    $product_id = intval( $coupon->get_meta('product_gift_single', true) );
    if ( ! $product_id ) return;

    $product = wc_get_product($product_id);
    if ( ! $product || ! $product->is_purchasable() || ! $product->is_in_stock() ) return;
    if ( ! WC()->cart ) return;

    foreach ( WC()->cart->get_cart() as $cart_item ) {
        if ( intval($cart_item['product_id']) === $product_id ) return;
    }

    WC()->cart->add_to_cart(
        $product_id,
        1,
        0,
        array(),
        array(
            'free_gift' => $coupon_code,
        )
    );
});

/* ----------------------------------------
 * 5. Удаляем подарок при удалении купона
 * ---------------------------------------- */
add_action('woocommerce_removed_coupon', function($coupon_code) {
    if ( empty($coupon_code) || ! WC()->cart ) return;

    foreach ( WC()->cart->get_cart() as $cart_key => $cart_item ) {
        if ( ! empty($cart_item['free_gift']) && $cart_item['free_gift'] === $coupon_code ) {
            WC()->cart->remove_cart_item( $cart_key );
        }
    }
});

/* ----------------------------------------
 * 6. Чистим подарок при загрузке корзины
 * ---------------------------------------- */
add_action('woocommerce_cart_loaded_from_session', function() {
    if ( ! WC()->cart ) return;

    $applied = WC()->cart->get_applied_coupons();
    foreach ( WC()->cart->get_cart() as $cart_key => $cart_item ) {
        if ( ! empty($cart_item['free_gift']) ) {
            if ( ! in_array( $cart_item['free_gift'], (array) $applied, true ) ) {
                WC()->cart->remove_cart_item( $cart_key );
            }
        }
    }
});

/* ----------------------------------------
 * 7. Цена подарка = 0
 * ---------------------------------------- */
add_filter('woocommerce_add_cart_item', function($cart_item) {
    if ( ! empty($cart_item['free_gift']) && isset($cart_item['data']) ) {
        // Установим цену товара в 0
        $cart_item['data']->set_price(0);

        // Защита: обеспечим наличие ключей line_total/line_subtotal
        if ( ! isset( $cart_item['line_total'] ) ) {
            $cart_item['line_total'] = 0;
        }
        if ( ! isset( $cart_item['line_subtotal'] ) ) {
            $cart_item['line_subtotal'] = 0;
        }
    }
    return $cart_item;
}, 20);

add_filter('woocommerce_get_cart_item_from_session', function($cart_item, $values) {
    if ( ! empty($values['free_gift']) ) {
        $cart_item['free_gift'] = $values['free_gift'];
        if ( isset($cart_item['data']) ) {
            $cart_item['data']->set_price(0);
        }

        // Защита: гарантируем числовые итоги для подарка
        if ( ! isset( $cart_item['line_total'] ) ) {
            $cart_item['line_total'] = 0;
        }
        if ( ! isset( $cart_item['line_subtotal'] ) ) {
            $cart_item['line_subtotal'] = 0;
        }
    }
    return $cart_item;
}, 20, 2);

/* ----------------------------------------
 * 8. Блокируем изменение количества
 * ---------------------------------------- */
add_filter('woocommerce_cart_item_quantity', function($product_quantity, $cart_item_key, $cart_item) {
    if ( ! empty($cart_item['free_gift']) ) {
        $qty = isset($cart_item['quantity']) ? intval($cart_item['quantity']) : 1;
        return '<input type="hidden" class="qty" name="cart[' . esc_attr($cart_item_key) . '][qty]" value="' . esc_attr($qty) . '">'
             . '<span class="gift-qty-display" aria-hidden="true">1</span>';
    }
    return $product_quantity;
}, 1000, 3);

/* ----------------------------------------
 * 9. Скрываем цену подарка
 * ---------------------------------------- */
add_filter('woocommerce_cart_item_price', function($price_html, $cart_item) {
    if ( ! empty($cart_item['free_gift']) ) return '';
    return $price_html;
}, 1000, 2);

/* ----------------------------------------
 * 10. Пишем "Подарок" в сумме
 * ---------------------------------------- */
add_filter('woocommerce_cart_item_subtotal', function($subtotal, $cart_item) {
    if ( ! empty($cart_item['free_gift']) ) return 'Подарок';
    return $subtotal;
}, 1000, 2);

/* ----------------------------------------
 * 11. Если подарок удалили — удаляем купон
 * ---------------------------------------- */
add_action('woocommerce_cart_item_removed', function($cart_item_key, $cart) {
    $removed = $cart->removed_cart_contents[ $cart_item_key ] ?? null;
    if ( ! $removed ) return;

    if ( ! empty($removed['free_gift']) ) {
        $coupon_code = $removed['free_gift'];
        if ( in_array($coupon_code, (array) $cart->get_applied_coupons(), true) ) {
            $cart->remove_coupon( $coupon_code );
            wc_add_notice('Купон удалён, так как подарок был удалён из корзины.', 'notice');
        }
    }
}, 10, 2);

/* ----------------------------------------
 * 12. Если товара в подарок нет в наличии выводим уведомление
 * ---------------------------------------- */
add_filter('woocommerce_coupon_is_valid', function($valid, $coupon, $discount) {
    if ( ! is_object($coupon) || ! $coupon->is_type('free_gift') ) {
        return $valid;
    }
    $product_id = intval($coupon->get_meta('product_gift_single', true));
    if ( ! $product_id ) {
        return $valid;
    }
    $product = wc_get_product($product_id);
    if ( ! $product || ! $product->is_purchasable() || ! $product->is_in_stock() ) {
        wc_add_notice(
            'Подарок по купону недоступен, так как товар закончился на складе.',
            'error'
        );
        return false; 
    }
    return $valid;
}, 10, 3);

Появится новый вид купона «Товар в подарок».

woocommerce товар в подарок

Сохраните (опубликуйте) купон, чтобы появилось поле для выбора товара.

woocommerce товар в подарок

Вот так выглядит в классической корзине применение купона:

woocommerce товар в подарок

Если товар в подарок закончится, то появится сообщение «Подарок по купону недоступен, так как товар закончился на складе.» Ведь в реальности товары в подарок не бесконечны =)

woocommerce товар в подарок в корзине

Также при удалении товара в подарок, будет удаляться купон. И при удалении купона — удаляться товар в подарок.

Если применили купон, а потом закончился товар в подарок, то купон просто сам удалится, а вместе с ним и товар (это стандартное поведение woocommerce при не выполнении условия купона).

Если сделать заказ с товаром в подарок, перейти в личный кабинет Заказы и нажать «Заказать снова», то этот товар попадёт в корзину. Поэтому цену товара в подарок ставьте не 0 руб, а обычную или высокую.

Либо можно вообще запретить покупать этот товар без купона, но надо будет немного изменить код.

Вот и всё, этот сниппет не повлияет на скорость и нагрузку сайта, безопасен, протестирован с woocommerce 10.3.5

Picture of Автор: Александра

Автор: Александра

@avsalexandra
Занимаюсь натуральным питанием собак и кошек BARF. Wordpress для души ☺️

Crocoblock
Elementor
Gutenberg
Jetengine
Jetformbuilder
profile builder
Woocommerce
Wordpress
WYSIWYG
Лейка
#автосохранение
#доменная почта
#рассылка
#бейдж
#благотворительность
#заказ ожидает
#подарок
#подчёркивание
#публикация постов
#видео
#пожертвования
#мультивыбор
#роли
#drag and drop
#изображения товаров
#подписки
#распродажа
#личный кабинет
#пагинация
#alt text
#галерея товара
#аватар
#возврат
#видео товара
#купон
#отменить заказ
Комментарии:

Добавить комментарий