Закрытый раздел для клиентов в WordPress за 20 минут
Личные страницы, роль «Клиент» и несколько хуков: гость попадает на форму входа, клиент работает без админ-панели и консоли. Всё это в одном плагине меньше чем на сто строк, без сторонних дополнений.

Через 20 минут на сайте появится раздел /klientam/: гость попадёт на форму входа, а клиент после логина увидит свои страницы без админ-панели и не откроет /wp-admin/. Понадобятся штатная видимость «Личное» и плагин меньше чем на сто строк. Инструкция для WordPress 6.x и PHP 7.4 или новее.
Что нужно до начала
- WordPress 6.x и учётная запись администратора.
- Доступ к файлам сайта по SFTP или через файловый менеджер хостинга: нужна папка
wp-content/plugins. - Постоянные ссылки любого вида, кроме «Простые» («Настройки → Постоянные ссылки»).
- Свежая резервная копия: опечатка в файле плагина может положить сайт до исправления.
Почему «Личное», а не редирект
Популярный рецепт: оставить страницу опубликованной и отправлять гостей на логин. Но текст останется доступным через REST API (/wp-json/wp/v2/pages), поиск и карту сайта. Статус «Личное» ядро проверяет само, поэтому дыр меньше, а кода тоже.
Редирект закрывает адрес. Статус «Личное» закрывает саму страницу.
Цена решения: право read_private_pages* откроет клиенту все личные страницы сайта, не только этот раздел. Служебные материалы для сотрудников держите в черновиках.
Код плагина
Создайте файл wp-content/plugins/client-area/client-area.php и вставьте код целиком. Он создаёт роль, отправляет гостей на вход, ведёт клиента в раздел после логина, закрывает консоль и прячет админ-панель.
<?php
/**
* Plugin Name: Client Area
* Description: Роль «Клиент» и закрытый раздел /klientam/.
* Version: 1.0.0
* Requires at least: 6.0
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
// Слаг родительской страницы раздела. Совпадает со слагом в админке.
const CA_AREA_SLUG = 'klientam';
function ca_is_client( $user ) {
return $user instanceof WP_User && in_array( 'client', (array) $user->roles, true );
}
// remove_role нужен, чтобы повторная активация обновляла права:
// add_role не меняет уже существующую роль.
register_activation_hook( __FILE__, 'ca_activate' );
function ca_activate() {
remove_role( 'client' );
add_role( 'client', 'Клиент', array(
'read' => true,
'read_private_pages' => true,
) );
}
// Личная страница для гостя отдаёт 404. Отправляем его на форму входа.
add_action( 'template_redirect', 'ca_redirect_guests' );
function ca_redirect_guests() {
global $wp;
if ( is_user_logged_in() || ! is_404() ) {
return;
}
$path = trim( $wp->request, '/' );
if ( $path === CA_AREA_SLUG || str_starts_with( $path, CA_AREA_SLUG . '/' ) ) {
$target = esc_url_raw( home_url( '/' . $path . '/' ) );
wp_safe_redirect( wp_login_url( $target ) );
exit;
}
}
// После входа клиент попадает в раздел, а не в консоль.
add_filter( 'login_redirect', 'ca_login_redirect', 10, 3 );
function ca_login_redirect( $redirect_to, $requested, $user ) {
if ( ca_is_client( $user ) && '' === $requested ) {
return home_url( '/' . CA_AREA_SLUG . '/' );
}
return $redirect_to;
}
// Консоль для клиента закрыта. AJAX пропускаем.
add_action( 'admin_init', 'ca_block_admin' );
function ca_block_admin() {
if ( ! wp_doing_ajax() && ca_is_client( wp_get_current_user() ) ) {
wp_safe_redirect( home_url( '/' . CA_AREA_SLUG . '/' ) );
exit;
}
}
// Админ-панель сверху клиенту не нужна.
add_filter( 'show_admin_bar', 'ca_hide_admin_bar' );
function ca_hide_admin_bar( $show ) {
return ca_is_client( wp_get_current_user() ) ? false : $show;
}
Шаги
- Положите файл. Создайте папку
client-areaвwp-content/pluginsи файл с кодом выше, кодировка UTF-8 без BOM. Проверка: в «Плагины → Установленные» появился Client Area. - Активируйте плагин. При активации создаётся роль. Проверка: в «Пользователи → Добавить» в списке ролей есть «Клиент».
- Создайте родительскую страницу. Заголовок «Клиентам», слаг
klientam, видимость «Личное», затем «Опубликовать». Проверка: под вашей учётной записью/klientam/открывается, в заголовке стоит приставка «Личное:». - Добавьте дочерние страницы. В поле «Родительская страница» выберите «Клиентам», видимость поставьте «Личное»: с родителя она не наследуется. Проверка: страница открывается у вас по адресу вида
/klientam/dokumenty/. - Создайте клиента. «Пользователи → Добавить», роль «Клиент», включите письмо новому пользователю. Проверка: в списке пользователей у него роль «Клиент».
- Проверьте всё в приватном окне браузера.
- Гость открывает
/klientam/: появляется форма входа. - Гость открывает
/wp-json/wp/v2/pages: страницы «Клиентам» в ответе нет. - Клиент входит: открывается
/klientam/, чёрной панели сверху нет. - Клиент открывает
/wp-admin/: его возвращает на/klientam/.
- Гость открывает
Что где задаётся
| Параметр | Значение | Где задаётся |
|---|---|---|
| Файл плагина | wp-content/plugins/client-area/client-area.php | файловая система |
| Слаг родителя | klientam | страница; равен CA_AREA_SLUG |
| Видимость | Личное | каждая страница отдельно |
| Роль клиента | Клиент (client) | профиль пользователя |
Если не получилось
- Гость видит 404 вместо формы входа. Слаг страницы не совпадает с
CA_AREA_SLUG, включены «Простые» ссылки или страницу отдаёт кеш. Сверьте слаг, пересохраните «Настройки → Постоянные ссылки», исключите/klientam/из кеша. - Клиент после входа видит 404. У роли нет
read_private_pages: она создана более ранней версией кода. Деактивируйте и снова активируйте плагин, роль пересоздастся. - «There has been a critical error on this website». Скорее всего, синтаксическая ошибка при копировании. Переименуйте папку плагина по SFTP, сайт заработает; сравните файл с кодом выше или откройте
wp-content/debug.logпри включённомWP_DEBUG_LOG. - «Cannot modify header information - headers already sent by (output started at ...client-area.php:1)». Перед
<?phpстоит пробел, пустая строка или BOM. Пересохраните файл в UTF-8 без BOM. - Гость открывает дочернюю страницу без входа. Она опубликована, а не личная. Смените видимость на «Личное».
Что делать дальше
- Вложения. Личная страница закрывает текст, но не файлы: ссылка вида
/wp-content/uploads/...открывается без входа тому, кто её знает. Договоры и счета в медиафайлы не кладите, им нужна отдельная схема выдачи. - Кеш. Исключите
/klientam/из полностраничного кеширования. - Пароли. Консоль закрыта, поэтому клиенты меняют пароль через «Забыли пароль?» на форме входа. Проверьте, что письма доходят.
- Что мерить. В логах доступа смотрите POST-запросы к
/wp-login.phpс ответом 200: так выглядят неудачные попытки входа, а резкий рост означает перебор паролей.
* Право (capability): разрешение на конкретное действие, например читать личные страницы. Роль: набор прав под именем. Пользователю назначают роль, а WordPress проверяет именно права.
Разрушитель авто-разводов: Фото заказ-наряда СТО: завышения, дубли работ, лишние позиции.
Спросить за 15 ₽Источники: WordPress Plugin Handbook: Roles and Capabilities, WordPress Code Reference: add_role()
Частые вопросы
Сработает ли код на WordPress 5.x?
Что ломается в проде после включения плагина?
Можно ли показывать разным клиентам разные страницы?
Что будет с клиентами, если отключить плагин?
Я всё сделал, а раздел не работает. С чего начать?
Достаточно ли этого, чтобы защитить договоры и счета клиентов?
Материал носит информационный характер и подготовлен редакцией «Агентуры». Он не является офертой, рекламой или индивидуальной консультацией. Упомянутые продукты, компании и торговые знаки принадлежат их правообладателям. Перед принятием решений, влекущих юридические или финансовые последствия, обратитесь к профильному специалисту.