Как ограничить доступ к курсам LearnPress по активному подписочному статусу WooCommerce

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

Ниже — рабочая схема без выдуманных API: используем стандартные возможности WordPress, WooCommerce и LearnPress, а логику доступа держим в отдельном мини-плагине. Это удобнее, чем править тему: после обновления всё останется на месте.

Когда это действительно нужно

Сценарий подходит, если у вас:

  • подписка оформляется через WooCommerce и доступ к курсу должен зависеть от её активности;
  • нужно закрывать курс сразу после отмены, возврата или окончания оплаченного периода;
  • часть материалов открыта только для действующих клиентов;
  • вы хотите избежать ручного удаления учащихся из курса.

Если у вас разовая оплата за курс, эта схема избыточна. Тогда лучше опираться на стандартную покупку курса через LearnPress или связку с WooCommerce без дополнительной проверки статуса.

Диагностика: где обычно ломается доступ

Перед внедрением проверьте, что именно сейчас происходит на сайте. Иначе легко исправить не ту точку.

Что проверить в админке

  • Есть ли у пользователя связанный заказ WooCommerce и какой у него статус: processing, completed, on-hold, cancelled, refunded.
  • Не выдаётся ли доступ к курсу вручную через LearnPress, минуя WooCommerce.
  • Нет ли кэша на страницах курса, который показывает старое состояние доступа.
  • Не используется ли отдельный плагин подписок, который уже хранит свой статус и может конфликтовать с вашей логикой.

Как быстро понять источник проблемы

Откройте курс под тестовым пользователем и сравните три состояния: активный заказ, отменённый заказ, возврат. Если страница курса открывается одинаково во всех случаях, значит проверка доступа вообще не выполняется. Если доступ пропадает не сразу, а через часы, проблема чаще всего в кэше или в том, что проверка завязана только на cron, а не на событие смены статуса заказа.

ПодходПлюсыМинусы
Плагин подписокУдобно для регулярных платежейЗависимость от конкретного расширения
Свой код в мини-плагинеКонтроль над логикой и статусамиНужно поддерживать самостоятельно
Только ручной доступ в LearnPressПросто настроитьНе подходит для автоматического снятия доступа

Пошаговое решение: проверяем активный статус заказа WooCommerce

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

Ниже пример мини-плагина. Он не привязан к конкретному расширению подписок, а работает на уровне заказов WooCommerce. Вам нужно подставить ID товара, который продаёт доступ к курсу.

<?php
/**
 * Plugin Name: LearnPress Access by WooCommerce Order
 * Description: Ограничивает доступ к курсу по активному заказу WooCommerce.
 */

if ( ! defined( 'ABSPATH' ) ) {
    exit;
}

function lpwc_user_has_active_access( $user_id, $product_id ) {
    if ( ! function_exists( 'wc_get_orders' ) ) {
        return false;
    }

    $orders = wc_get_orders( array(
        'customer_id' => $user_id,
        'status'       => array( 'processing', 'completed' ),
        'limit'        => -1,
        'return'       => 'ids',
    ) );

    if ( empty( $orders ) ) {
        return false;
    }

    foreach ( $orders as $order_id ) {
        $order = wc_get_order( $order_id );
        if ( ! $order ) {
            continue;
        }

        foreach ( $order->get_items() as $item ) {
            if ( (int) $item->get_product_id() === (int) $product_id ) {
                return true;
            }
        }
    }

    return false;
}

Дальше нужно не просто проверить заказ, а закрыть сам курс или отдельные страницы уроков. Самый практичный путь — перехватывать просмотр курса и отправлять пользователя на страницу с сообщением о необходимости продлить доступ.

<?php
function lpwc_restrict_course_access() {
    if ( ! is_user_logged_in() || ! function_exists( 'learn_press_get_course' ) ) {
        return;
    }

    if ( ! is_singular( 'lp_course' ) ) {
        return;
    }

    $course_id  = get_the_ID();
    $user_id    = get_current_user_id();
    $product_id = (int) get_post_meta( $course_id, '_lpwc_product_id', true );

    if ( ! $product_id ) {
        return;
    }

    if ( lpwc_user_has_active_access( $user_id, $product_id ) ) {
        return;
    }

    wp_safe_redirect( home_url( '/renew-access/' ) );
    exit;
}
add_action( 'template_redirect', 'lpwc_restrict_course_access' );

Здесь используется метаполе _lpwc_product_id, в котором вы храните ID WooCommerce-товара, связанного с курсом. Это удобно: один курс — один товар, и логика остаётся прозрачной.

Как связать курс и товар без лишней магии

Чтобы не хардкодить ID в коде, добавьте поле в карточку курса в админке и сохраняйте туда ID товара. Для этого можно использовать стандартные метабоксы WordPress. Ниже упрощённый пример: он добавляет поле в редактор курса LearnPress и сохраняет значение в пост-мета.

<?php
function lpwc_add_course_product_meta_box() {
    add_meta_box(
        'lpwc_course_product',
        'WooCommerce товар для доступа',
        'lpwc_course_product_meta_box_html',
        'lp_course',
        'side',
        'default'
    );
}
add_action( 'add_meta_boxes', 'lpwc_add_course_product_meta_box' );

function lpwc_course_product_meta_box_html( $post ) {
    $value = get_post_meta( $post->ID, '_lpwc_product_id', true );
    wp_nonce_field( 'lpwc_save_course_product', 'lpwc_course_product_nonce' );
    echo '<p><label for="lpwc_product_id">ID товара</label>';
    echo '<input type="number" id="lpwc_product_id" name="lpwc_product_id" value="' . esc_attr( $value ) . '" style="width:100%" /></p>';
}

function lpwc_save_course_product_meta( $post_id ) {
    if ( ! isset( $_POST['lpwc_course_product_nonce'] ) || ! wp_verify_nonce( $_POST['lpwc_course_product_nonce'], 'lpwc_save_course_product' ) ) {
        return;
    }

    if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
        return;
    }

    if ( isset( $_POST['lpwc_product_id'] ) ) {
        update_post_meta( $post_id, '_lpwc_product_id', absint( $_POST['lpwc_product_id'] ) );
    }
}
add_action( 'save_post_lp_course', 'lpwc_save_course_product_meta' );

Если доступ должен сниматься сразу после отмены или возврата

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

Для этого удобнее реагировать на смену статуса заказа WooCommerce. Важно не делать это на каждом запросе: достаточно отработать один раз в момент изменения статуса.

<?php
function lpwc_handle_order_status_change( $order_id, $old_status, $new_status, $order ) {
    if ( ! $order instanceof WC_Order ) {
        $order = wc_get_order( $order_id );
    }

    if ( ! $order ) {
        return;
    }

    $user_id = $order->get_user_id();
    if ( ! $user_id ) {
        return;
    }

    $blocked_statuses = array( 'cancelled', 'refunded', 'failed' );

    if ( ! in_array( $new_status, $blocked_statuses, true ) ) {
        return;
    }

    foreach ( $order->get_items() as $item ) {
        $product_id = (int) $item->get_product_id();
        // Здесь можно связать товар с курсом и снять доступ.
        // Например, удалить запись о доступе или отправить пользователя на страницу продления.
    }
}
add_action( 'woocommerce_order_status_changed', 'lpwc_handle_order_status_change', 10, 4 );

Если у вас уже есть логика выдачи доступа через LearnPress, не дублируйте её в нескольких местах. Лучше выбрать один источник истины: либо заказ WooCommerce, либо отдельная таблица/мета со статусом доступа. Иначе через месяц появятся расхождения, когда курс открыт, а заказ уже отменён.

Проверка результата после внедрения

После установки мини-плагина не ограничивайтесь визуальной проверкой на одной странице. Пройдите короткий тестовый сценарий:

  • создайте тестового пользователя;
  • оформите заказ на товар, связанный с курсом;
  • убедитесь, что курс и уроки открываются;
  • смените статус заказа на cancelled или refunded;
  • обновите страницу курса в приватном окне;
  • проверьте, что редирект на страницу продления срабатывает;
  • посмотрите, не остались ли открытыми прямые ссылки на уроки.

Если доступ закрывается только на странице курса, но уроки открываются напрямую, значит проверка стоит слишком высоко в шаблоне. В таком случае её нужно дублировать на уровне single-шаблона урока или в логике доступа LearnPress, а не только на странице курса.

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

Проверяют только статус заказа, но не товар в заказе

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

Ставят проверку в шаблон темы

После обновления темы код исчезает. Для такой логики нужен отдельный мини-плагин или mu-plugin.

Не учитывают кэш

Если страницы курса кэшируются, пользователь может видеть старую версию доступа. Исключите страницы курса, уроков и страницу продления из кэша.

Снимают доступ только по cron

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

Не проверяют гостевой доступ

Если курс открыт для незалогиненных пользователей, редирект не сработает. В этом случае нужно отдельно закрывать контент через шаблон или настройки LearnPress.

Безопасность и производительность

Логика доступа должна быть простой и предсказуемой. Не делайте тяжёлый запрос ко всем заказам пользователя на каждом хите, если у вас большой магазин. Для активных подписок лучше хранить промежуточный флаг доступа в user meta и обновлять его при смене статуса заказа. Это снизит нагрузку на базу.

Также проверьте три вещи:

  • все входные данные проходят через absint(), sanitize_text_field() или аналогичную очистку;
  • в метабоксах используются nonce-проверки;
  • редиректы выполняются через wp_safe_redirect(), а не через произвольный header().

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

Когда лучше не писать код, а взять готовый инструмент

Если вам нужна не просто проверка заказа, а полноценная подписочная модель с продлением, паузой, заморозкой и уведомлениями, самописная связка быстро разрастается. В такой ситуации разумнее опереться на специализированный плагин подписок WooCommerce и уже поверх него строить доступ к LearnPress.

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

Добавь в закладки и поделись с друзьями:

⭐⭐⭐⭐⭐
Как автоматизировать создание курсов в LearnPress через импорт CSV
08.04.2026
Как добавить разные типы вопросов в Quizle для LearnPress
20.02.2026
Как решить проблему неотображения последних пройденных уроков в LearnPress
09.07.2026
Как добавить многоуровневую навигацию в курсах LearnPress
05.01.2026
Решение проблемы конфликта стандартных платежных шаблонов WooCommerce с LearnPress
31.05.2026
×
до 3225₽

WPShop - честная партнерка!

Зарабатывай с каждой продажи

Подключиться ⋙