wpupdate.ru wordpress WP Update

Как отключить покупку отдельных товаров для неавторизованных пользователей в WooCommerce

Сценарий простой: часть товаров должна быть видна в каталоге, но купить их могут только авторизованные пользователи. Это часто нужно для оптовых цен, закрытых коллекций, B2B-каталога или товаров, доступных только после входа в аккаунт. Если ограничить доступ только на уровне страницы товара, гости всё равно увидят кнопку покупки в каталоге, а иногда смогут добавить товар в корзину через прямую ссылку. Поэтому лучше закрывать сценарий целиком: и отображение кнопки, и попытку добавления в корзину, и переход к оформлению.

Как понять, где именно ломается ограничение

Перед правкой кода проверьте, что именно сейчас происходит у гостя. В WooCommerce ограничения могут работать частично: кнопка скрыта, но товар всё ещё добавляется по прямому запросу; или наоборот, товар отображается как недоступный, но ссылка на карточку не защищена. Это важно, потому что решение зависит от точки входа.

Что проверить в первую очередь

  • Показывается ли кнопка Добавить в корзину в каталоге и на странице товара.
  • Можно ли открыть URL товара в режиме инкогнито и увидеть кнопку покупки.
  • Добавляется ли товар в корзину через прямую ссылку вида ?add-to-cart=ID.
  • Не мешают ли кэш-плагин или серверный кэш: иногда гостю отдается уже сгенерированная страница с кнопкой.
  • Есть ли у товара вариации: для них нужно отдельно проверить вывод кнопки и формы выбора.

Если ограничение должно действовать только для части товаров, удобнее пометить их отдельной категорией или кастомным полем. Для примера ниже будем использовать категорию private. Это проще поддерживать, чем хардкодить ID в нескольких местах.

Рабочее решение через хуки WooCommerce

Ниже вариант без плагинов: скрываем кнопку покупки для гостей, блокируем добавление в корзину и показываем понятное сообщение. Код лучше добавить в дочернюю тему или в небольшой mu-plugin, чтобы он не потерялся при обновлении темы.

<?php
/**
 * Ограничение покупки товаров из категории private для неавторизованных пользователей.
 */

add_filter( 'woocommerce_is_purchasable', 'wpupdate_restrict_guest_purchase', 10, 2 );
function wpupdate_restrict_guest_purchase( $purchasable, $product ) {
    if ( is_user_logged_in() ) {
        return $purchasable;
    }

    if ( has_term( 'private', 'product_cat', $product->get_id() ) ) {
        return false;
    }

    return $purchasable;
}

add_filter( 'woocommerce_loop_add_to_cart_link', 'wpupdate_hide_loop_add_to_cart_for_guests', 10, 2 );
function wpupdate_hide_loop_add_to_cart_for_guests( $html, $product ) {
    if ( is_user_logged_in() ) {
        return $html;
    }

    if ( has_term( 'private', 'product_cat', $product->get_id() ) ) {
        return '<a class="button" href="' . esc_url( wc_get_page_permalink( 'myaccount' ) ) . '">Войдите, чтобы купить</a>';
    }

    return $html;
}

add_filter( 'woocommerce_add_to_cart_validation', 'wpupdate_block_guest_add_to_cart', 10, 3 );
function wpupdate_block_guest_add_to_cart( $passed, $product_id, $quantity ) {
    if ( is_user_logged_in() ) {
        return $passed;
    }

    if ( has_term( 'private', 'product_cat', $product_id ) ) {
        wc_add_notice( 'Для покупки этого товара нужно войти в аккаунт.', 'error' );
        return false;
    }

    return $passed;
}

add_action( 'woocommerce_single_product_summary', 'wpupdate_guest_purchase_notice', 25 );
function wpupdate_guest_purchase_notice() {
    if ( is_user_logged_in() ) {
        return;
    }

    global $product;

    if ( $product && has_term( 'private', 'product_cat', $product->get_id() ) ) {
        echo '<p class="woocommerce-info">Этот товар доступен только после входа в аккаунт.</p>';
    }
}

Что делает этот набор хуков:

  • woocommerce_is_purchasable отключает саму возможность покупки;
  • woocommerce_loop_add_to_cart_link меняет кнопку в каталоге;
  • woocommerce_add_to_cart_validation страхует прямое добавление в корзину;
  • woocommerce_single_product_summary выводит сообщение на карточке товара.

Если нужно ограничить не по категории, а по списку товаров

Иногда удобнее задать массив ID, особенно если закрытых товаров немного и они не объединены в отдельную категорию. Логика та же, меняется только условие. Такой подход проще для точечных исключений, но хуже масштабируется, если товаров станет много.

<?php
function wpupdate_is_restricted_product( $product_id ) {
    $restricted_ids = array( 123, 456, 789 );
    return in_array( (int) $product_id, $restricted_ids, true );
}

Дальше в хуках вместо has_term() вызываете wpupdate_is_restricted_product(). Это удобно, если товар может находиться в нескольких категориях и ограничение не должно зависеть от структуры каталога.

Сравнение подходов: плагин, код, гибрид

Если задача временная или админка должна управлять ограничением без разработчика, можно взять плагин. Но для точного контроля над UX и логикой покупки код обычно надежнее. Ниже короткое сравнение.

Подход Плюсы Минусы
Плагин ограничения доступа Быстро включить, часто есть настройки по ролям и категориям Может конфликтовать с темой, лишняя нагрузка, меньше контроля над сообщениями и кнопками
Код через хуки WooCommerce Точный контроль, минимум лишней логики, проще отлаживать Нужен доступ к коду и базовое понимание WordPress
Гибрид Плагин для ролей и админки, код для блокировки покупки и текста Больше точек поддержки, важно не дублировать правила

Как проверить, что ограничение работает

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

  1. Откройте сайт в режиме инкогнито.
  2. Перейдите в карточку товара из категории private.
  3. Убедитесь, что кнопка покупки заменена на сообщение или ссылку на вход.
  4. Попробуйте добавить товар через прямую ссылку ?add-to-cart=ID.
  5. Проверьте, что в корзину товар не попал и показано уведомление об ошибке.
  6. Войдите под тестовой учетной записью и повторите те же шаги: покупка должна снова работать.

Если у вас включен кэш страниц, отдельно проверьте, что гостю не отдается закэшированная версия с кнопкой покупки. Для WooCommerce это особенно важно на страницах каталога и карточек товара. Иногда проблему решает исключение страниц магазина, корзины, оформления и аккаунта из кэша, но для закрытых товаров этого может быть недостаточно — нужно смотреть, кэшируется ли сам товарный архив.

Частые ошибки и как их исправить

На практике проблемы обычно не в самом хуке, а в том, что ограничение применяется не в той точке или не учитывает вариации и кэш.

Кнопка скрыта, но товар всё равно покупается

Значит, вы поменяли только вывод кнопки в шаблоне. Обязательно добавьте проверку через woocommerce_add_to_cart_validation и woocommerce_is_purchasable. Без этого прямой запрос в корзину может пройти.

Ограничение не срабатывает для вариативных товаров

У вариативного товара проверку лучше делать по родительскому товару, но в некоторых шаблонах и плагинах в фильтры попадает ID вариации. Если условие не срабатывает, проверьте, какой именно ID приходит в ваш callback, и при необходимости поднимайтесь к родительскому товару через wp_get_post_parent_id().

Гость видит старую кнопку из кэша

Это типичная ошибка при использовании page cache или CDN. Для таких страниц либо отключайте кэширование для гостевых товарных страниц, либо делайте ограничение на серверной стороне так, чтобы оно не зависело от уже сгенерированного HTML. Код выше как раз помогает, потому что блокирует покупку не только визуально, но и на уровне валидации.

Сообщение слишком общее и не помогает пользователю

Фраза вроде «Доступ запрещён» хуже, чем конкретная подсказка. Лучше сразу написать, что нужно войти в аккаунт, и дать ссылку на страницу входа. Это снижает количество лишних обращений в поддержку.

Практические советы по безопасности и производительности

Если ограничение завязано на роли пользователей, не храните логику в нескольких плагинах одновременно. Дублирующиеся правила часто дают неожиданный результат: один плагин скрывает кнопку, другой разрешает покупку через AJAX, а третий меняет текст в каталоге. Для поддержки проще оставить один источник истины.

  • Добавляйте код в дочернюю тему или mu-plugin, а не в основной файл темы.
  • Не используйте тяжелые запросы к базе на каждом рендере карточки товара, если можно обойтись категорией или ID.
  • Проверяйте поведение на мобильной версии: иногда тема выводит отдельную кнопку для sticky bar или quick view.
  • Если ограничение нужно только для части каталога, не закрывайте весь магазин целиком — это ухудшает UX и усложняет поддержку.

Если вам нужен более широкий контроль над служебными элементами WooCommerce и чисткой лишнего кода, иногда удобно смотреть в сторону инструментов вроде Clearfy Pro: у него есть функции для удаления дублей и оптимизации сайта, но саму логику ограничения покупки всё равно лучше держать в коде, если она завязана на бизнес-правила.

Когда лучше не писать код вручную

Если у вас сложная матрица доступов — разные роли, разные страны, разные типы товаров и отдельные правила для подписок — лучше сначала описать логику на бумаге или в таблице. В таких сценариях код без структуры быстро превращается в набор исключений. Тогда уже имеет смысл либо делать собственный мини-плагин, либо брать специализированное решение с админскими настройками и оставлять код только для точечных доработок.

Но для типовой задачи «гости видят товар, но купить могут только после входа» достаточно одного аккуратного набора хуков. Главное — не ограничиваться скрытием кнопки и обязательно проверить прямое добавление в корзину.

×

AI-плагин от WPShop.ru

анализирует конкурентов

пишет статьи

готовит SEO

генерирует изображения

и еще кое-что...
WPGPT
Плагин, который наполняет ваш сайт WordPress
Узнать больше