Режим Multisite позволяет использовать одну установку WordPress для нескольких сайтов одновременно. При этом каждый сайт получает свои собственные таблицы в базе данных с уникальным префиксом.
Таблицы с данными зарегистрированных пользователей общие для всех сайтов сети. Это несомненный плюс и зарегистрировавшись однажды можно получить доступ к нескольким сайтам. Причем на каждом сайте один и тот же аккаунт может иметь разные права. Например, на одном сайте пользователь может быть редактором, а на другом администратором.
В обычной установке WordPress страницу регистрации, авторизации и сброса пароля выводит файл wp-login.php
.
wp-login.php
— авторизацияwp-login.php?action=register
— регистрацияwp-login.php?action=lostpassword
— сброс пароля
В режиме Multisite ядро WordPress начинает вести себя несколько иначе и при переходе по ссылке wp-login.php?action=register
произойдет редирект на wp-signup.php
. Это страница регистрации вашей сети, которая по умолчанию есть в WordPress.
Помимо регистрации обычных пользовательских аккаунтов на ней можно создать и новый сайт, если суперадминистратор включил такую возможность в настройках сети (Network Admin → Settings → Network Settings).
В большинстве тем страница регистрации выглядит не совсем хорошо. Многие темы оформления используют CSS-фреймворки, например, Bootstrap, и собственные специфичные классы для стилизации разных элементов на страницах, поэтому тяжело написать единый HTML, который подойдет всем.
Но не стоит отчаиваться, если страница выглядит неопрятно. Файл wp-signup.php
отличная вещь на первых порах, когда нет времени прорабатывать каждую деталь сайта — можно сосредоточиться на других более важных страницах и контенте.
Когда вы будете готовы сделать свою собственную страницу регистрации, wp-signup.php
будет хорошим образцом и примером, по которому легко разобраться в спектре функций, которые предоставляет WordPress для обработки и проверки введенных пользователями данных и создания новых аккаунтов.
Основной сайт сети
По умолчанию, WordPress открывает страницу регистрации (wp-signup.php
) на основном домене (сайте) сети. Тем не менее, можно создавать страницы регистрации для каждого сайта сети, даже если у них разные домены и темы.
Мы будем рассматривать случай, когда на всех сайтах сети используется одна тема, но на каждом из них есть страница регистрации. Сайты различаются языком (английский и русский), поэтому страница регистрации будет выводиться на «родном» языке сайта. В случае, если сайты используют разные темы, все будет зависеть от того, какие именно это темы, подойдет ли им одинаковая верстка (отличная ситуация, которая может подтолкнуть вас к унификации всех своих тем) или стоит прорабатывать страницы индивидуально.
Альтернатива functions.php
Файл functions.php
знаком многим пользователям WordPress благодаря событиям и фильтрам, с помощью которых очень просто вносить правки. В нашем случае, с учетом того, что функционал регистрации рассчитан на несколько сайтов, имеет смысл вынести его в MU-плагины.
Что такое MU-плагины?
MU-плагины (Must Use Plugins) загружаются при открытии любого сайта сети. Их нельзя отключить или включить в административной части WordPress, они работают всегда. Стоит отметить, что MU-плагины загружаются раньше обычных плагинов, тем оформления и до полной загрузки ядра WordPress, поэтому вызов некоторых функций может привести к фатальным ошибкам в PHP.
Подобная «ранняя» загрузка имеет и свои плюсы. Скажем, внутри любой темы нельзя цепляться к некоторым событиям из плагинов, которые срабатывают еще до загрузки functions.php
.
В Jetpack, например, есть события вида jetpack_module_loaded_related-posts
(related-posts
— название модуля), с помощью которых можно отслеживать активность модулей. К этому событию невозможно «прицепиться» из functions.php
, потому что оно срабатывает еще до загрузки темы — плагины загружаются раньше тем.
Взглянуть на общую картинку порядка загрузки WordPress и возникновения событий можно на странице Action Reference в Кодексе.
Порядок в файлах
MU-плагины могут содержать любое количество файлов и структуру, которая покажется вам логичной. Я придерживаюсь примерно такой иерархии:
| mu-plugins | | load.php | | selena-network | | | signup | | | | plugin.php | | | ... | | | jetpack | | | | plugin.php
В файле load.php
подключаются переводы и все необходимые «плагины»:
// Загрузка переводов для MU-плагинов load_muplugin_textdomain( 'selena_network', '/selena-network/languages/' ); // Функционал для страницы регистрации require WPMU_PLUGIN_DIR . '/selena-network/signup/plugin.php'; // Еще один плагин // require WPMU_PLUGIN_DIR ...
Внутри директории selena-network
хранятся папки плагинов. В каждой есть свой plugin.php
, которые мы и подключаем в load.php
. Это дает гибкость и возможность мгновенно отключать и включать отдельные компоненты на рабочем проекте в случае экстренной необходимости.
Страница регистрации
Разобравшись с тем, где и как мы будем писать код, можно переходить к созданию страницы регистрации.
Создадим страницу с адресом example.org/signup/
через обычный интерфейс. В качестве адреса можно использовать любой URL, который покажется подходящим для вашего проекта.
Редирект на нужную страницу регистрации
Чтобы WordPress узнал о нашей новой странице регистрации и производил редирект именно на нее, при клике на ссылку «Зарегистрироваться», используется фильтр wp_signup_location
. Его можно найти внутри wp-login.php
и именно он отвечает за редирект на wp-signup.php
по умолчанию.
case 'register' : if ( is_multisite() ) { wp_redirect( apply_filters( 'wp_signup_location', network_site_url( 'wp-signup.php' ) ) ); exit; // ...
Как вы помните, по умолчанию, страница регистрации открывается на основном домене сети. Именно поэтому здесь используется network_site_url()
.
Добавим свой обработчик к фильтру в mu-plugins/selena-network/signup/plugin.php
, который будет отдавать адрес страницы регистрации на текущем сайте:
function selena_network_signup_page( $url ) { return home_url( 'signup' ); } add_filter ('wp_signup_location', 'selena_network_signup_page', 99);
selena_network
— префикс, который я использую в именах всех функций внутри MU-плагинов на своем сайте для избежания коллизий, его следует заменить на свой собственный уникальный префикс. Приоритет добавления фильтра 99, потому что некоторые плагины, например, bbPress и BuddyPress могут перезаписать этот адрес на свой собственный (MU-плагины загружаются раньше, чем обычные плагины, см. выше).
Обратите внимание, что используется home_url()
, которая в отличие от network_site_url()
, отдает адрес текущего сайта, а не главного сайта сети.
Функционал wp-signup.php
Файл wp-signup.php
содержит большое количество функций и кода. Чтобы увидеть картину в целом можно воспользоваться сворачиванием кода. Как правило, по-английски это называется «code folding».
В самом начале файла с 1 по 80 строчку (в версии 4.1.1) производятся различные проверки и вывод «старта» страницы с помощью get_header()
.
Далее объявляются множество методов и перед тем, как мы начнем работать с ними, стоит разобраться что делает каждая функция. Внутри многих из них часто используются другие функции с префиксом wpmu_
, все они объявляются в файле wp-includes/ms-functions.php
. Этот раздел тяжело понять не видя код самостоятельно. Ниже небольшое описание основных функций на случай, если у вас возникнут затруднения.
wpmu_signup_stylesheet()
— вывод дополнительного CSS на странице регистрации.show_blog_form()
— поля для регистрации сайта (адрес, название видимость для поисковых систем).validate_blog_form()
— проверка введенного адреса сайта и названия с помощьюwpmu_validate_blog_signup()
.show_user_form()
— поля для регистрации пользователя (логин и адрес эл. почты).validate_user_form()
— проверка введенного логина и адреса эл. почты с помощьюwpmu_validate_user_signup()
.signup_another_blog()
— поля для регистрации новых сайтов с помощьюshow_blog_form()
для пользователей, которые уже зарегистрированы на сайте.validate_another_blog_signup()
— проверяет адрес сайта и название с помощьюvalidate_blog_form()
.signup_user()
— основная функция для вывода полей страницы регистрации.validate_user_signup()
— проверяет логин и адрес эл. почты с помощьюvalidate_user_form()
.signup_blog()
— поля для ввода адреса, названия и видимости сайта (второй шаг регистрации) с помощьюshow_blog_form()
.validate_blog_signup()
— проверяет логин, адрес эл. почты, адрес и название сайта.
В самом низу файла wp-signup.php
(со строчки 646 в версии 4.1.1) основная логика работы страницы регистрации, которая использует все выше описанные методы. Эта часть кода не вынесена в функцию. В конце вызывается get_footer()
.
Копируем функционал wp-signup.php
Далее будет описана процедура копирования wp-signup.php
в MU-плагины и внесению изменений в «форк». Возможно, это может показаться не самым правильным путем. Вместо этого можно с нуля написать свои функции для проверки и вывода форм используя классы, а не обычные функции. На мой взгляд в wp-signup.php
уже есть вся необходимая логика для нашей страницы, остается лишь внести небольшие изменения.
При обновлении WordPress время от времени меняется и wp-signup.php
, но это не значит что при каждом релизе придется синхронизировать свой «форк». Функции внутри wp-signup.php
по сути занимаются лишь выводом HTML, проверкой данных, созданием учетных записей и сайтов занимаются методы с префиксом wpmu_
, объявленные в ms-functions.php
.
Займемся созданием функции, которая будет выводить форму регистрации на странице. Для этого скопируем wp-signup.php из
корня WordPress в mu-plugings/selena-network/signup/
. Подключим его внутри mu-plugins/selena-network/signup/plugin.php
).
require WPMU_PLUGIN_DIR . '/selena-network/signup/wp-signup.php';
Удалим из самого начала скопированного файла все require и ненужные проверки. В версии 4.1.1 это весь код с 1 по 80 строчку.
Теперь мы готовы создать главную функцию для вывода формы регистрации. Для этого всю логику со строчки 646 и до самого конца файла перенесем в функцию c названием selena_network_signup_main
. В самом конце удалим два лишних закрывающих </div>
(строчки 722 и 723), а также вызов get_footer()
.
В только что созданной selena_network_signup_main()
в самом начале объявим глобальную переменную active_signup
, которую используют все остальные методы из этого файла. И добавим вызов события before_signup_form
, которое мы удалили из самого начала файла.
function selena_network_signup_main() { global $active_signup; do_action( 'before_signup_form' ); // ... }
Теперь остается лишь изменить верстку во всех местах где это необходимо и страница регистрации готова.
Для наглядности я опубликовал свою версию измененного wp-signup.php
на Github.
Вывод формы регистрации
Здесь есть как минимум два варианта. Более удобный способ — создать шорткод [network_signup]
и разместить его на странице через обычный редактор.
// Создаем шорткод network_signup add_shortcode( 'network_signup', 'selena_network_signup_main' );
Второй вариант — создать в папке дочерней темы шаблон страницы page-signup.php
. Вместо слова «signup» можно использовать уникальный ID, присвоенный странице. Внутри шаблона добавить необходимую верстку и сделать вызов selena_network_signup_main()
в нужном месте.
В результате моя страница регистрации стала выглядеть намного лучше и чище.
Страница активации
По умолчанию WordPress условно делит процесс регистрации в Multisite на два шага — заполнение формы на сайте и активация аккаунта при переходе по ссылке отправленной в электронном письме. После того, как вы заполните форму, созданную в предыдущем разделе, WordPress отправляет письмо с небольшой инструкцией и ссылкой для активации аккаунта.
За вывод страницы активации отвечает файл wp-activate.php
расположенный в корневой директории WordPress. wp-activate.php
можно так же полностью изменить. Процесс схож с тем, что мы уже делали для wp-signup.php
.
Создадим страницу example.org/activate/
через обычный интерфейс. В качестве адреса используйте любой URL, который покажется вам подходящим.
Скопируем файл wp-activate.php
к себе в MU-плагины и подключим его в mu-plugins/selena-network/signup/plugin.php
.
require WPMU_PLUGIN_DIR . '/selena-network/signup/wp-activate.php';
Внутри не так много содержимого, в отличие от wp-signup.php
. Файл выполняет единственную операцию — активирует аккаунт, если получен верный ключ и выводит сообщение об ошибке или успешном выполнении операции.
Удалим все ненужные проверки и require
— с 1 по 69 строчку в WordPress 4.1.1. В самом конце уберем вызов get_footer()
. Оставшееся содержимое перенесем в функцию selena_network_activate_main()
.
Интересно заметить, что здесь перед загрузкой WordPress (wp-load.php) объявлялась константа WP_INSTALLING
. Ее наличие заставляет WordPress не загружать плагины.
Как и в случае со страницей регистрации остается лишь исправить верстку там, где это необходимо. Также можно изменить текст выводимых сообщений (в этом случае не забудьте добавить текстовый домен своих MU-плагинов во все функции-переводчики, по умолчанию он нигде не установлен).
Готовую функцию можно использовать на заранее созданной странице через шорткод или отдельный шаблон в дочерней теме.
Финальный вариант wp-activate.php на Github.
Письма активации с правильными ссылками
Страница активации готова к работе, но WordPress не знает о ней и по прежнему будет отправлять письма активации со ссылкой на wp-activate.php
. В отличие от wp-signup.php
здесь нет фильтра, который бы позволил изменить адрес. Вместо этого нужно написать свою функцию, которая будет отправлять письма с правильными ссылками.
В момент заполнения и отправки формы на странице регистрации WordPress вызывает wpmu_signup_user()
или wpmu_signup_blog()
в зависимости от типа регистрации. Обе функции создают новую запись в таблице wp_signups
заполняя ее необходимым содержимым, среди которого есть и ключ активации аккаунта.
После, в зависимости от функции, вызывается wpmu_signup_user_notification()
или wpmu_signup_blog_notification()
. Обе функции имеют схожий функционал — генерируют и отправляют письмо со ссылкой активации, но принимают разные аргументы. В обоих есть фильтры для «перехвата» события.
if ( ! apply_filters( 'wpmu_signup_user_notification', $user, $user_email, $key, $meta ) ) return false;
Для активации аккаунтов с созданием блога:
if ( ! apply_filters( 'wpmu_signup_blog_notification', $domain, $path, $title, $user, $user_email, $key, $meta ) ) { return false; }
Остается лишь написать свои обработчики, внутри которых отправлять письма через wp_mail()
, а в самом конце обязательно отдавать false
, чтобы WordPress не отправил письмо активации дважды — одно ваше, другое — письмо по умолчанию со ссылкой на wp-activate.php
.
function selena_network_wpmu_signup_user_notification( $user, $user_email, $key, $meta = array() ) { // Генерируем заголовок, текст и заголовки письма // ... // Отправляем письмо или добавляем Cron-задачу для отправки письма wp_mail( $user_email, wp_specialchars_decode( $subject ), $message, $message_headers ); // Отдаем false, чтобы WordPress не отправил письмо активации дважды return false; } add_filter( 'wpmu_signup_user_notification', 'selena_network_wpmu_signup_user_notification', 10, 4 );
Если вы отправляете письма через SMTP-сервер или количество регистраций очень велико, следует задуматься о том, чтобы не отправлять письма мгновенно. Вместо этого можно добавлять Cron-задачи с помощью WordPress Cron.
Закрываем доступ к wp-signup.php и wp-activate.php
Создав свои собственные страницы регистрации и активации, может потребоваться закрыть «оригиналы». Например, если на странице регистрации есть дополнительные поля, которые необходимо обязательно заполнить. Также многие WordPress сайты подвергаются спам-регистрациям.
Решить две проблемы одним действием можно попросив Apache отдавать 404 в случае попытки открытия этих страниц. Для этого нужно лишь прописать пару дополнительных RewriteRule
в ваш файл-конфигурацию или .htaccess
.
RewriteEngine On RewriteBase / # Знание регулярных выражений никогда не будет лишним :) RewriteRule ^wp-signup\.php - [R=404,L] RewriteRule ^wp-activate\.php - [R=404,L] # BEGIN WordPress # Правила от WordPress по умолчанию не трогаем :) # ... # END WordPress
Заключение
Для этой и многих других «проблем» связанных с WordPress в интернете есть множество решений. Например, для создания страниц регистрации и активации некоторые предлагают переписывать оригинальные wp-signup.php
и wp-activate.php
. Этого не стоит делать, потому что в случае обновления WordPress вы потеряете все изменения, внесенные в файлы, а также не сможете, проверить целостность ядра с помощью WP-CLI.
При разработке любого дополнения, темы или решения следует потратить немного времени на то, чтобы разобраться с тем, что происходит внутри WordPress. Для этого есть множество полезных дебаг-инструментов.
P.S.
Для автоматического назначения разных ролей новым пользователям можно использовать плагин Multisite User Management.
Если у вас возникли вопросы или трудности во время создания страниц регистрации и активации после прочтения статьи, оставьте комментарий и мы обязательно ответим.