Как сделать кастомные чекбоксы согласий в WooCommerce

от Михаил | Июл 29, 2026 | Уроки

Просто повесить один чекбокс «Я согласен с правилами» уже недостаточно — особенно если вы хотите разделять обязательные юридические согласия (оферта, ПДн) и маркетинг (рассылки).

Делюсь проверенным решением, которое решает эту задачу «под ключ» для классического чекаута WooCommerce [woocommerce_checkout].

Как это работает

  • Шаг 1. Вывод полей — перед кнопкой «Оформить заказ» выводим кастомные чекбоксы. Если страница перезагрузится из-за ошибки, выбранные состояния сохранятся.
  • Шаг 2. Валидация — проверяем, отмечены ли обязательные галочки. Если нет — выводим системное уведомление WooCommerce и останавливаем оформление.
  • Шаг 3. Сохранение — записываем метаданные прямо в объект заказа перед его сохранением в БД.
  • Шаг 4. Админка — выводим статус всех согласий прямо в карточку заказа под адресом плательщика.
  • Шаг 5. Чистка — полностью убираем стандартную логику термсов.

Весь код сниппета целиком

<?php
/**
 * Добавляем чекбоксы согласия на странице оформления заказа WooCommerce
 * и сохраняем их с поддержкой HPOS и классического хранилища (Post Meta).
 *
 * - Обязательные: оферта, политика конфиденциальности
 * - Необязательный: согласие на рекламные рассылки
 *
 * ВАЖНО: код рассчитан на классический чекаут WooCommerce (шорткод [woocommerce_checkout]).
 * Если магазин использует новый чекаут на блоках (Cart & Checkout Blocks), эти хуки не сработают.
 */

if ( ! defined( 'ABSPATH' ) ) {
    exit; // Защита от прямого доступа
}

// 1. Выводим чекбоксы перед кнопкой "Оформить заказ"
add_action( 'woocommerce_review_order_before_submit', 'rb_add_agreement_checkboxes', 20 );
function rb_add_agreement_checkboxes() {

    $oferta_checked    = ! empty( $_POST['rb_oferta_agree'] ) ? 1 : 0;
    $privacy_checked   = ! empty( $_POST['rb_privacy_agree'] ) ? 1 : 0;
    $marketing_checked = ! empty( $_POST['rb_marketing_agree'] ) ? 1 : 0;

    ?>
    <div class="rb-agreement-checkboxes" style="margin-bottom: 15px;">

        <p class="form-row validate-required" style="margin-bottom: 8px;">
            <label class="woocommerce-form__label woocommerce-form__label-for-checkbox checkbox">
                <input type="checkbox"
                       name="rb_oferta_agree"
                       id="rb_oferta_agree"
                       value="1"
                       <?php checked( $oferta_checked, 1 ); ?> />
                <span>
                    Вы согласны с условиями
                    <a href="https://moysite.com/oferta/" target="_blank" rel="noopener">публичной оферты</a>
                    <span class="required">*</span>
                </span>
            </label>
        </p>

        <p class="form-row validate-required" style="margin-bottom: 8px;">
            <label class="woocommerce-form__label woocommerce-form__label-for-checkbox checkbox">
                <input type="checkbox"
                       name="rb_privacy_agree"
                       id="rb_privacy_agree"
                       value="1"
                       <?php checked( $privacy_checked, 1 ); ?> />
                <span>
                    Вы согласны с
                    <a href="https://moysite.com/privacy-policy/" target="_blank" rel="noopener">политикой конфиденциальности</a>
                    и обработкой персональных данных
                    <span class="required">*</span>
                </span>
            </label>
        </p>

        <p class="form-row" style="margin-bottom: 8px;">
            <label class="woocommerce-form__label woocommerce-form__label-for-checkbox checkbox">
                <input type="checkbox"
                       name="rb_marketing_agree"
                       id="rb_marketing_agree"
                       value="1"
                       <?php checked( $marketing_checked, 1 ); ?> />
                <span>
                    Вы согласны получать рекламные и информационные сообщения от Продавца.
                </span>
            </label>
        </p>

    </div>
    <?php
}

// 2. Валидация — не даём оформить заказ, если обязательные галочки не отмечены
add_action( 'woocommerce_checkout_process', 'rb_validate_agreement_checkboxes' );
function rb_validate_agreement_checkboxes() {

    if ( empty( $_POST['rb_oferta_agree'] ) ) {
        wc_add_notice(
            'Пожалуйста, подтвердите согласие с условиями публичной оферты.',
            'error'
        );
    }

    if ( empty( $_POST['rb_privacy_agree'] ) ) {
        wc_add_notice(
            'Пожалуйста, подтвердите согласие с политикой конфиденциальности.',
            'error'
        );
    }
}

// 3. Сохранение данных заказа (совместимо с HPOS и со старой базой CPT)
add_action( 'woocommerce_checkout_create_order', 'rb_save_agreement_checkboxes', 10, 2 );
function rb_save_agreement_checkboxes( $order, $data ) {

    $now = current_time( 'mysql' );

    // Оферта
    if ( ! empty( $_POST['rb_oferta_agree'] ) ) {
        $order->update_meta_data( '_rb_oferta_agree', 'yes' );
        $order->update_meta_data( '_rb_oferta_agree_date', $now );
    } else {
        $order->update_meta_data( '_rb_oferta_agree', 'no' );
    }

    // Политика конфиденциальности
    if ( ! empty( $_POST['rb_privacy_agree'] ) ) {
        $order->update_meta_data( '_rb_privacy_agree', 'yes' );
        $order->update_meta_data( '_rb_privacy_agree_date', $now );
    } else {
        $order->update_meta_data( '_rb_privacy_agree', 'no' );
    }

    // Маркетинговые рассылки
    $marketing_agree = ! empty( $_POST['rb_marketing_agree'] ) ? 'yes' : 'no';
    $order->update_meta_data( '_rb_marketing_agree', $marketing_agree );
    $order->update_meta_data( '_rb_marketing_agree_date', $now );
}

// 4. Вывод метаданных в админ-панели заказа (совместимо с HPOS и CPT)
add_action( 'woocommerce_admin_order_data_after_billing_address', 'rb_show_agreement_in_admin' );
function rb_show_agreement_in_admin( $order ) {

    // Хук всегда передаёт объект WC_Order, но на всякий случай подстрахуемся
    // от нестандартных вызовов (например, сторонними плагинами).
    if ( ! is_a( $order, 'WC_Order' ) ) {
        return;
    }

    $oferta    = $order->get_meta( '_rb_oferta_agree' );
    $privacy   = $order->get_meta( '_rb_privacy_agree' );
    $marketing = $order->get_meta( '_rb_marketing_agree' );

    echo '<div class="address" style="clear:both; padding-top:10px;">';
    echo '<p><strong>Согласие с офертой:</strong> ' . ( $oferta === 'yes' ? 'Да' : 'Нет' ) . '</p>';
    echo '<p><strong>Согласие с политикой конфиденциальности:</strong> ' . ( $privacy === 'yes' ? 'Да' : 'Нет' ) . '</p>';
    echo '<p><strong>Согласие на рекламные рассылки:</strong> ' . ( $marketing === 'yes' ? 'Да' : 'Нет' ) . '</p>';
    echo '</div>';
}

// 5. Полностью убираем стандартный чекбокс "terms" WooCommerce
add_filter( 'woocommerce_get_terms_page_id', '__return_zero' );

Разбор кода по шагам.

Разберём каждую секцию, чтобы было понятно, за что отвечает каждый hook и каждая строчка.

Предотвращение прямого доступа

PHP

if ( ! defined( 'ABSPATH' ) ) {
    exit; // Защита от прямого доступа
}
  • Зачем нужно: Стандартная практика безопасности в WordPress. Если кто-то попытается открыть этот файл напрямую через браузер (по прямому URL-адресу), скрипт просто завершит работу, не раскрывая структуру сервера и потенциальные ошибки.

Шаг 1: Вывод чекбоксов на странице чекаута

PHP

add_action( 'woocommerce_review_order_before_submit', 'rb_add_agreement_checkboxes', 20 );
  • Хук: woocommerce_review_order_before_submit помещает наш HTML-блок в форме оформления заказа непосредственно перед кнопкой «Оформить заказ».
  • Приоритет 20: Гарантирует, что наши поля появятся после большинства стандартных элементов блока оплаты.

PHP

$oferta_checked    = ! empty( $_POST['rb_oferta_agree'] ) ? 1 : 0;
$privacy_checked   = ! empty( $_POST['rb_privacy_agree'] ) ? 1 : 0;
$marketing_checked = ! empty( $_POST['rb_marketing_agree'] ) ? 1 : 0;
  • Сохранение состояния: Если пользователь совершит ошибку (например, забудет ввести телефон) и страница перезагрузится через AJAX, поля не сбросятся. Код подтянет значения из $_POST и сохранит галочки там, где клиент их уже поставил.

PHP

<input type="checkbox" name="rb_oferta_agree" id="rb_oferta_agree" value="1" <?php checked( $oferta_checked, 1 ); ?> />
  • Функция checked(): Стандартная функция WordPress, которая сравнивает два значения и выводит checked='checked', если они совпадают.

Шаг 2: Валидация перед созданием заказа

PHP

add_action( 'woocommerce_checkout_process', 'rb_validate_agreement_checkboxes' );
  • Хук: woocommerce_checkout_process срабатывает в момент, когда пользователь нажимает кнопку «Оформить заказ», но до того, как заказ создаётся в базе данных.
  • Логика:PHPif ( empty( $_POST['rb_oferta_agree'] ) ) { wc_add_notice( 'Пожалуйста, подтвердите согласие с условиями публичной оферты.', 'error' ); } Если обязательный чекбокс не отмечен, функция wc_add_notice() добавляет ошибку в глобальный стек WooCommerce. Оформление заказа прерывается, а покупатель видит красное уведомление.
  • Маркетинговый чекбокс: Не участвует в валидации, так как по закону согласие на рекламные рассылки должно быть добровольным.

Шаг 3: Сохранение данных заказа и поддержке HPOS

PHP

add_action( 'woocommerce_checkout_create_order', 'rb_save_agreement_checkboxes', 10, 2 );
  • Хук: woocommerce_checkout_create_order дает доступ к объекту заказа $order (экземпляр класса WC_Order) перед его записью в БД.
  • Фиксация времени ($now):PHP$now = current_time( 'mysql' ); Записывается точное время согласия. Это ключевой момент для юридической защиты на случай проверок или споров.

Почему это работает с HPOS (High-Performance Order Storage)?

В современных версиях WooCommerce данные заказов хранятся в отдельных таблицах, а не в привычном wp_postmeta.

  • Правильный подход (использован в коде): PHP $order->update_meta_data( '_rb_oferta_agree', 'yes' ); $order->update_meta_data( '_rb_oferta_agree_date', $now ); Метод CRUD API $order->update_meta_data() абстрагирует работу с БД. WooCommerce сам решает, куда именно записать данные — в старый postmeta или в новую структуру HPOS.

💡 Префикс _ (нижнее подчёркивание): Использование префикса _rb_ делает эти метаданные «скрытыми» по умолчанию, чтобы они не замусоривали стандартный интерфейс произвольных полей WordPress.

Шаг 4: Отображение данных в админке

PHP

add_action( 'woocommerce_admin_order_data_after_billing_address', 'rb_show_agreement_in_admin' );
  • Хук: woocommerce_admin_order_data_after_billing_address встраивает наш HTML-блок в панель управления заказом — сразу под блоком «Адрес плательщика».
  • Проверка типа объекта:PHPif ( ! is_a( $order, 'WC_Order' ) ) { return; } Защита от сбоев. Если сторонний плагин вызовет этот хук и передаст не объект заказа, код корректно завершит работу без фатальной ошибки (Fatal Error).
  • Чтение данных:PHP$oferta = $order->get_meta( '_rb_oferta_agree' ); Снова используется стандартный метод $order->get_meta(), гарантирующий корректную чтение как с HPOS, так и без него.
Как сделать кастомные чекбоксы согласий в WooCommerce

Шаг 5: Отключение стандартных «Термсов» WooCommerce

PHP

add_filter( 'woocommerce_get_terms_page_id', '__return_zero' );
  • Зачем нужно: У WooCommerce есть встроенный функционал чекбокса "Terms and Conditions". Если он включен в настройках магазина, то на чекауте появится дублирующий чекбокс.
  • Как работает: Данный фильтр принудительно заставляет WooCommerce считать, что страница условий не задана (0), благодаря чему встроенный чекбокс полностью скрывается, уступая место нашей кастомной системе.

Как внедрить на сайт

  1. Скопируйте весь код.
  2. Откройте файл functions.php вашей активной дочерней темы (или используйте плагин Code Snippets).
  3. Замените URL-адреса https://moysite.com/ на ссылки вашего проекта.
  4. Вставьте код и сохраните изменения.

Было полезно?

Пожалуйста, расскажите об этом друзьям!

VK
Pinterest
OK
Telegram
Linkedin
WhatsApp
Viber
Reddit

* Meta / Facebook — сервисы, предоставляемые организацией, признанной экстремистской

Готовы получать больше клиентов?

Ваш сайт может быть не просто визиткой, а полноценным инструментом продаж — работать 24/7, привлекать заявки и усиливать доверие к вашему бизнесу. Оставьте заявку — и мы подскажем, какое решение подойдёт именно вам.

Вам может быть интересно

Telegram Почта info@pureseo.ru Телефон +7 (903) 757-15-01