WooCommerce

Кнопка «Перейти в корзину» вместо «В корзину», если товар уже добавлен: WooCommerce без правки шаблонов

M
Markabus
·
Фотореалистичный кадр рабочего стола: на переднем плане проволочная магазинная корзинка с серым керамическим чайником на упаковочной бумаге, за ней открытый ноутбук с карточкой того же чайника, где под ценой контурная кнопка с иконкой корзины и стрелкой вместо обычной кнопки покупки — иллюстрация к статье о замене кнопки «В корзину» на «Перейти в корзину» для товаров, уже добавленных в корзину WooCommerce.

Товар уже лежит в корзине, но карточка об этом не знает и снова предлагает «В корзину». Покупатель нажимает второй раз — и получает две штуки вместо одной, а потом разбирается с количеством на странице оформления. Логичнее показать ему другую кнопку: «Перейти в корзину». Сделать это можно хуками, не трогая файлы шаблонов, — и для карточки товара, и для кнопок в каталоге.

Как узнать, что товар уже в корзине

У объекта корзины есть метод find_product_in_cart(). Он принимает идентификатор позиции корзины, который строится из ID товара функцией generate_cart_id(), и возвращает ключ позиции либо пустую строку. Вынесем проверку в отдельную функцию, чтобы использовать её в нескольких местах:

// Возвращает true, если простой товар уже есть в корзине
function shop_product_in_cart( $product_id ) {
    if ( ! WC()->cart ) {
        return false; // в админке и REST-запросах корзины может не быть
    }

    $cart_id = WC()->cart->generate_cart_id( $product_id );

    return (bool) WC()->cart->find_product_in_cart( $cart_id );
}

Проверка работает для простых товаров. У вариативных в корзине лежит конкретная вариация, и сравнивать пришлось бы её ID и атрибуты — в карточке товара до выбора вариации это не имеет смысла, поэтому дальше речь о простых товарах.

Карточка товара

Кнопку в карточке выводит функция woocommerce_template_single_add_to_cart, подключённая к хуку woocommerce_single_product_summary с приоритетом 30. Если товар уже в корзине, снимаем её с хука и ставим на то же место свою ссылку. Делаем это на том же хуке, но раньше — с приоритетом 1, когда объект товара уже известен:

add_action( 'woocommerce_single_product_summary', 'shop_swap_add_to_cart_button', 1 );
function shop_swap_add_to_cart_button() {
    global $product;

    if ( ! $product || ! $product->is_type( 'simple' ) || ! shop_product_in_cart( $product->get_id() ) ) {
        return;
    }

    remove_action( 'woocommerce_single_product_summary', 'woocommerce_template_single_add_to_cart', 30 );
    add_action( 'woocommerce_single_product_summary', 'shop_go_to_cart_button', 30 );
}

function shop_go_to_cart_button() {
    printf(
        '<a href="%s" class="single_add_to_cart_button button alt">%s</a>',
        esc_url( wc_get_cart_url() ),
        esc_html__( 'Перейти в корзину', 'shop' )
    );
}

Ссылка получает те же классы, что и стандартная кнопка, поэтому выглядит как она. Адрес корзины берётся из wc_get_cart_url(), а не пишется вручную: у корзины может быть другой ярлык, а у сайта — подпапка или несколько языков.

Кнопки в каталоге

В списках товаров кнопка формируется фильтром woocommerce_loop_add_to_cart_link, и заменить её ещё проще:

add_filter( 'woocommerce_loop_add_to_cart_link', 'shop_loop_go_to_cart_link', 10, 2 );
function shop_loop_go_to_cart_link( $html, $product ) {
    if ( ! $product->is_type( 'simple' ) || ! shop_product_in_cart( $product->get_id() ) ) {
        return $html;
    }

    return sprintf(
        '<a href="%s" class="button">%s</a>',
        esc_url( wc_get_cart_url() ),
        esc_html__( 'Перейти в корзину', 'shop' )
    );
}

Ajax-добавление в каталоге

В каталоге товар обычно добавляется без перезагрузки страницы, и после клика наша PHP-подмена сработает только при следующем открытии страницы. Чтобы кнопка менялась сразу, подпишитесь на событие added_to_cart, которое WooCommerce отправляет после успешного добавления, вместе со ссылкой на нажатую кнопку:

jQuery( function( $ ) {
    $( document.body ).on( 'added_to_cart', function( event, fragments, hash, $button ) {
        if ( ! $button || ! $button.length ) {
            return;
        }
        $button.replaceWith(
            '<a href="' + wc_add_to_cart_params.cart_url + '" class="button">Перейти в корзину</a>'
        );
    } );
} );

Адрес корзины здесь уже есть в объекте wc_add_to_cart_params, который WooCommerce передаёт своему скрипту добавления в корзину. Подключите этот код на страницах каталога с зависимостью от wc-add-to-cart.

Подводный камень: кеширование страниц

Содержимое корзины у каждого покупателя своё, а страница товара с такой подменой становится персональной. Если на сайте включён кеш страниц — плагин кеширования или CDN, — первый посетитель с товаром в корзине «запишет» в кеш версию с «Перейти в корзину», и её увидят все остальные. Вариантов два: исключить страницы товаров из кеша (дорого для нагрузки) или делать подмену на стороне браузера. Во втором случае PHP-часть не нужна: скрипт запрашивает содержимое корзины и меняет кнопки сам. Данные о корзине WooCommerce уже отдаёт на каждой странице через фрагменты (wc_fragments), а на новых версиях — через Store API по адресу /wp-json/wc/store/v1/cart. Для магазина без кеша страниц хуки выше — самый простой и надёжный путь.

Блочные темы

В блочных темах карточку товара собирает блок «Добавить в корзину с опциями». В ранних версиях он выводил те же PHP-шаблоны, и хук из раздела про карточку работал; в новых версиях WooCommerce блок переписан и рендерится иначе. После обновления проверьте страницу товара: если подмена перестала работать, используйте вариант со скриптом.

Коротко

Проверить, есть ли товар в корзине, помогает find_product_in_cart(). В карточке товара стандартную кнопку снимают с хука woocommerce_single_product_summary и ставят ссылку на wc_get_cart_url(), в каталоге — подменяют через фильтр woocommerce_loop_add_to_cart_link и дополняют обработчиком события added_to_cart. При включённом кеше страниц подмену переносят в браузер.

Частые вопросы

Q.Как проверить, что товар уже в корзине WooCommerce?

WC()->cart->find_product_in_cart( WC()->cart->generate_cart_id( $product_id ) ) вернёт ключ позиции, если товар есть, и пустую строку, если нет. Перед вызовом проверьте, что объект корзины существует.

Q.Почему не править шаблон simple.php в теме?

Переопределённый шаблон перестаёт получать обновления WooCommerce, и его придётся сверять с каждой версией. Хуки дают тот же результат и не зависят от разметки шаблона.

Q.Кнопка в каталоге меняется только после перезагрузки — почему?

В каталоге товар добавляется через Ajax, и PHP-подмена срабатывает только при следующей загрузке страницы. Добавьте обработчик события added_to_cart, который заменит нажатую кнопку сразу.

Q.Все посетители видят «Перейти в корзину», хотя корзина пуста — в чём дело?

Страница товара попала в кеш страниц с версией для покупателя, у которого товар был в корзине. Исключите страницы товаров из кеша или перенесите подмену кнопки в браузер, опираясь на данные корзины из Store API.

Источники

Поделиться:OKVK