Регистрирует функцию, которая будет срабатывать во время активации плагина.
Эта функция прикрепляет указанную callback функцию к хуку activate_(plugin) и является оберткой для этого хука.
(plugin) в хуке activate_(plugin) заменяется названием относительного пусти до главного файла плагина. Например, если плагин расположен: wp-content/plugins/sampleplugin/sample.php , то название хука будет: activate_sampleplugin/sample.php .
С версии 3.1. хук срабатывает только во время активации плагина, и не срабатывает во время автоматического обновления плагина.
Как это работает
Плагин активируется функцией activate_plugin() , в которой срабатывает хук activate_(plugin) .
Функция activate_plugin() в ядре вызывается уже после загрузки среды ВП . Эта функция подключает главный файл плагина (и все что в нем указано), а затем через хук активирует указанную callback-функцию. За счет этого в нашей callback-функции доступны все функции и классы плагина. Но, так как все основные хуки WP уже сработали во время загрузки среды ВП, то никакие события плагина повешенные на хуки, например plugins_loaded , уже не сработают при подключении главного файла плагина. А значит наш плагин будет подключен, но не полностью: не так как он должен подключаться, когда уже активирован.
Так, например, если плагин делает что-либо во время события plugins_loaded , то все эти действия просто не произойдут при активации плагина. Например, если он подключает файл перевода, то файл перевода не будут подключен в момент срабатывания callback-функции указанной для register_activation_hook() .
Как правило, после срабатывания callback-функции есть 2 события на которые можно повесить функции: activated_plugin и shutdown .
Чтобы сделать что-то неординарное при активации плагина, смотрите пример 5.
Правила использования
Функция не будет работать, если вызвать её в момент срабатывания какого-либо хука, например plugins_loaded , init . Функция должна вызываться напрямую из главного файла плагина. Правила активации:
- Глобальные переменные (если они есть) должны быть определены явно, чтобы был доступ к ним из функции хука.
register_activation_hook() должен вызываться из основного файла плагина, из того где расположена директива Plugin Name: ... и не должна вызываться из какого-либо хука, вроде plugins_loaded или init .
Функция хука должна быть в том же файле что и хук или подключаться заранее из другого файла.
В функции хука не работает вывод на экран (echo). Потому что происходит редирект и echo вы не увидите. Но можно использовать die() .
Заметка про область переменных
При активации плагина, главный файл плагина подключается не в глобальной области, а внутри функции activate_plugin() . Поэтому переменные, которые в обычном режиме работы плагина считаются глобальными, не будут глобальными.
Так, функция, которая используется в register_activation_hook() может не видеть глобальные переменные, даже если вы объявили их как глобальные внутри этой функции. Пример:
$myvar = "что-то"; register_activation_hook(__FILE__, "myplugin_activate"); function myplugin_activate(){ global $myvar; echo $myvar; // Переменная не равна "что-то" }
Из-за этой особенности, глобальные переменные всегда нужно указывать явно. Все глобальные переменные должны быть определены как глобальные, даже если переменная указывается в теле плагина. Только в этом случае будет доступ к ним где угодно. Пример:
Global $myvar; // указываем явно что это глобальная переменная $myvar = "что-то"; register_activation_hook(__FILE__, "myplugin_activate"); function myplugin_activate(){ global $myvar; echo $myvar; //> что-то }
Хуков нет.
Возвращает
null. Ничего не возвращает.
Использование
register_activation_hook($file, $function); $file(строка) (обязательный) Путь до главного php файла плагина включая название самого плагина. Обычно используется волшебная константа PHP __FILE__ . $function(строка/массив/лямбда) (обязательный)Название функции обратного вызова. Для классов используйте массив: array($this, "название_функции"); .
Функция получит логическую переменную $network_wide - активируется ли плагин для всей сети сайтов, при мультисайте.
Примеры
#1. Запуск функции при активации плагина
Предположим у нас есть функция my_plugin_activate() в основном файле плагина: wp-content/plugins/myplugin/myplugin.php , тогда для запуска этой функции во время активации плагина используйте такой код:
Register_activation_hook(__FILE__, "my_plugin_activate"); function my_plugin_activate() { // Код активации... }
#2. Запуск метода класса
Если плагин использует PHP класс, код активации добавляется так:
Register_activation_hook(__FILE__, array("My_Plugin", "install")); class My_Plugin { static function install() { // Не создавайте здесь никакого вывода... } }
#3. Запуск метода класса из отдельного файла
Если класс, который содержит функцию активации находится в отдельном файле, то регистрируйте функцию активации так:
Include_once __DIR__ . "/class-My_Plugin.php"; register_activation_hook(__FILE__, array("My_Plugin", "on_activate_function"));
#4. Запуск метода класса из самого класса
Если вы находитесь внутри __construct() . Важно, __FILE__ должен «смотреть» на главный файл плагина:
Register_activation_hook(__FILE__, array($this, "YOUR_METHOD_NAME"));
#5 Делаем что-либо сразу после активации плагина
После активации плагина срабатывают только два хука: activated_plugin и shutdown .
Когда нужно что-либо сделать сразу после активации плагина, можно прицепить функцию к ним.
Когда такое решение не подходит, можно использовать опции WP: сохранять данные в опцию и затем проверять наличие опции, и делать что-либо, если опция есть:
// Основной файл плагина. ... function my_plugin_activate() { // добавляем опцию, чтобы потом если она есть сделать что-либо. add_option("Activated_Plugin", "Plugin-Slug"); // Здесь код активации... } register_activation_hook(__FILE__, "my_plugin_activate"); function load_plugin() { if (is_admin() && get_option("Activated_Plugin") == "Plugin-Slug") { // удаляем добавленную опцию, чтобы она больше не срабатывала // и делаем что нужно... delete_option("Activated_Plugin"); // Делаем что-либо единожды, после активации плагина // Например: add_action("init", "my_init_function"); } } add_action("admin_init", "load_plugin");
Другой вариант сделать что-то во время активации плагина - это создать свое событие так:
Function my_plugin_activate(){ // Устанавливаем свой хук, чтобы к нему можно было прицепиться из файлов самого плагина do_action("my_plugin_activate"); } register_activation_hook(__FILE__, "my_plugin_activate");
#6 Еще демонстрация использования функции
Небольшой плагин, демонстрирующий как нужно использовать функцию:
/* Plugin Name: A Test Description: A Test */ require_once dirname(__FILE__) . "/my_other_file.php"; /* Этот код не будет работать. Хук активации должен вызываться из основного файла. register_activation_hook (dirname(__FILE__) . "/my_other_file.php", "my_other_function"); */ // Это рабочий код. register_activation_hook(__FILE__, "test_activated"); /* Это правильный вариант объявления и доступа к глобальным переменным. Глобальные переменные должны объявляться четко. Без этого у вас не будет доступа к ним. */ global $some_var; $some_var = "hey"; // Функция активации function test_activated(){ // тут $some_var не будет равно hey global $some_var; // А тут $some_var будет равно hey // Эта функция определена в файле "my_other_file.php" my_other_function(); /* Этот вариант не будет работать. Если нужно записать логи во временный файл, используйте fopen/fwrite. Если вы хотите проверить, работает ли хук активации, используйте exit() внутри функции хука. */ echo "test_activated called!"; }
Создаем собственную страницу регистрации для мультисайта взамен стандартной wp-signup.php .
В обычной установке WordPress страницу регистрации (авторизации, сброса пароля) выводит файл wp-login.php .
- /wp-login.php - авторизация
- /wp-login.php?action=register - регистрация
- /wp-login.php?action=lostpassword - сброс пароля
Для мультисайта в wp-login.php есть отдельные условия. Так, при переходе по ссылке /wp-login.php?action=register на мультисайте, WordPress сделает редирект на страницу /wp-signup.php . Во многих темах страница выглядит не очень привлекательно, поэтому мы сделаем свою собственную.
Основной сайт сети
По умолчанию, WordPress открывает страницу регистрации (wp-signup.php) на основном домене (сайте) сети. Тем не менее, можно сделать отдельную страницу регистрации для каждого сайта сети, даже если у них разные темы. Мы будем рассматривать случай, когда на всех сайтах сети есть своя собственная страница регистрации, но используется одинаковая тема и сайты различаются лишь языком. Если используются разные темы, потребуется написать больше кода.
functions.php?
Нет. Имя этого файла, кажется, упоминается в любой статье про WordPress. В нашем случае, с учетом того, что функционал регистрации рассчитан на несколько сайтов, имеет смысл вынести его в MU-плагины, которые загружаются при открытии любого сайта.
Лирическое отступление
Стоит отметить, что MU-плагины загружаются раньше обычных плагинов и до полной загрузки ядра WordPress, поэтому вызов некоторых функций может привести к фатальным ошибкам в PHP. Подобная «ранняя» загрузка имеет и свои плюсы. Скажем внутри любой темы нельзя цепляться к некоторым экшенам, которые срабатывают еще до загрузки файла functions.php из темы. Примером этого могут служить экшены из плагина Jetpack вида jetpack_module_loaded_related-posts (related-posts - название модуля) с помощью которых возможно отслеживать активность модулей в Jetpack. К этому экшену невозможно «прицепиться» из файла темы, потому что экшен уже сработал до загрузки темы - плагины загружаются раньше тем. Взглянуть на общую картинку порядка загрузки WordPress можно на странице Action Reference в кодексе .
Порядок в файлах
MU-плагины могут содержать любое количество файлов и любую стуктуру, которая покажется вам логичной. Я придерживаюсь примерно такой иерархии:
|-mu-plugins |-|-load.php |-|-|-selena-network |-|-|-|-signup |-|-|-|-|-plugin.php |-|-|-|-|-... |-|-|-|-jetpack |-|-|-|-|-plugin.php
В файле load.php подключаются все необходимые «плагины» для нашей сети:
// Load Traslates for all addons load_muplugin_textdomain ("selena_network", "/selena-network/languages/"); // Network Signup require WPMU_PLUGIN_DIR . "/selena-network/signup/plugin.php"; // Another plugins // require WPMU_PLUGIN_DIR ...
Внутри папки selena-network хранятся папки плагинов, в каждой есть свой plugin.php , которые мы и подключаем в load.php . Это дает гибкость и возможность быстро отключать и включать некоторые вещи.
Адрес страницы регистрации
Чтобы указать адрес страницы регистрации, используется фильтр 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;
Добавим свою функцию в 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() , чтобы оставить посетителя на том же домене. В качестве адреса можно использовать любой URL.
Создание страницы
Теперь создадим страницу с адресом site.com/signup/ через обычный интерфейс, а в папке дочерней темы шаблон для нашей новой страницы - page-signup.php . Вместо слова «signup» можно использовать уникальный ID.
Внутри нового шаблона необходимо выполнить вызов функции selena_network_signup_main() , которая будет выводить форму регистрации.
Стоит заметить, что весь процесс с шаблонами не обязателен и вместо этого можно создать свой шорткод, который будет также вызывать функцию selena_network_signup_main() .
wp-signup.php и wp-activate.php
Теперь займемся созданием функции, которая будет выводить форму регистрации. Для этого скопируем файлы wp-signup.php и wp-activate.php из корня WordPress в mu-plugings/selena-network/signup/ (и не забываем их подключить внутри mu-plugins/selena-network/signup/plugin.php). Дальнейшие манипуляции с файлами крайне сложно и долго описывать, поэтому прийдется сделать их самостоятельно. Я лишь опишу что именно надо сделать и опубликую исходные файлы своего проекта:
- В начале файла удалить все require , вызов функций и прочий код вне функций.
- Переименовать все функции, добавив к именам уникальные префиксы.
- Нижнюю часть кода wp-signup.php обернуть в функцию selena_network_signup_main и в ее самом начале написать global $active_signup; .
- Заменить верстку на свою собственную в нужных местах.
Внутри wp-activate.php необходимо сделать примерно тоже самое:
- Удалить весь код вне функций, обернуть верстку в отдельную функцию.
- Изменить верстку в местах, где это необходимо.
Файл wp-activate.php отвечает за страницу активации аккаунта. Как и со страницей регистрации для нее необходимо создать отдельный шаблон, внутри которого вызывать функцию из файла wp-activate.php .
Отправляем письма активации
Страница регистрации отправляет посетителю письмо со ссылкой на активацию аккаунта. По умолчанию этим занимается функция wpmu_signup_user_notification() из файла ms-functions.php . Ее функционал можно заимствовать для своей функции. Причина, по которой необходимо отказаться от использования этой функции - она отправляет ссылку активации аккаунта с wp-activate.php . «Выключить» же эту функцию можно с помощью фильтра wpmu_signup_user_notification отдавая по нему false (если этого не cделать, письмо активации будет отправляться дважды, окей, на самом деле два разных письма).
Function armyofselenagomez_wpmu_signup_user_notification($user, $user_email, $key, $meta = array()) { // ... // Код из функции wpmu_signup_user_notification() wp_mail($user_email, wp_specialchars_decode($subject), $message, $message_headers); return false; } add_filter("wpmu_signup_user_notification", "armyofselenagomez_wpmu_signup_user_notification", 10, 4);
В результате страница регистрации в теме Селена стала выглядеть намного чище и аккуратней.
Заключение
В интернете множество других не очень правильных способов того, как сделать тоже самое - редиректы Apache, AJAX-формы, которые не будут работать без Java Script и т. п. Все это мне не очень понравилось, поэтому я постарался сделать это максимально правильно на своем собственном сайте.
Замечу, что править файлы следует осторожно и стараться не сильно отходить от исходных, чтобы в дальнешйем, в случае если WordPress изменит файлы wp-signup.php и wp-activate.php , их проще было сравнивать между собой для поиска изменений.
Не забывайте смотреть в исходный код всех описанных выше функций, чтобы полностью разобраться с тем, что и как происходит внутри кода.
Бонус. Защита от спамеров
Даже самые маленькие сайты на WordPress часто подвергаются налету спам-регистраций. Можно писать бесконечные условия для фильтрации ботов, зачастую больше похожие на попытку создать искусственный интеллект 🙂 В случае мультисайта мне очень помог обычный редирект в Apache, с помощью которого при открытии /wp-signup.php и /wp-acitvate.php я попросил выдавать 404 (я не эксперт по настройке Apache, поэтому мои правила могут быть не очень правильными).
RewriteEngine On RewriteBase / RewriteRule ^wp-signup\.php - RewriteRule ^wp-activate\.php - # BEGIN WordPress # Правила от WordPress по умолчанию не трогаем:) # ... # END WordPress
P. S. Я стараюсь максимально детально описывать некоторые сторонние вещи, потому что когда начинал я, порой некому было подсказать и объяснить многие вещи. Также я считаю, что подобные небольшие наводки на другие материалы кого-нибудь подтолкнут к изучению чего-то нового и расширению своей области знаний. В записях RewriteRule используются регулярные выражения, они совсем не сложные, например, символ ^ означает начало строки.
Позволяет использовать одну установку 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
Порядок в файлах
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 . В самом конце удалим два лишних закрывающих