Объявление activate php. Использование библиотеки TGM Plugin Activation в своих темах WordPress
Темы обычно не являются функциональными, однако иной раз нам, разработчикам, требуется внедрить некоторые возможности в нашу тему, чтобы сделать ее чуть лучше и удобнее.
В этом руководстве мы рассмотрим термин «территория плагинов», а также научимся использовать фантастический инструмент, написанный Томасом Гриффином: библиотеку TGM Plugin Activation.
Функциональность темы: вторжение на территорию плагинов
Темы предназначены для того, чтобы изменить дизайн веб-сайта WordPress. В идеале тема должна затрагивать только визуальный аспект. Однако в нашем «золотом веке» WordPress разработчики плагинов зачастую включают в свои темы функциональные особенности, которые позволяют сохранить конкурентоспособность на рынке.
Это вторжение на территорию плагинов. Мы можем представить «территорию плагинов», как некоторые функциональные участки кода. Любой фрагмент кода, меняющий функциональность вашего сайта, должен быть представлен в виде плагина, если указанный код не заложен в ядро WordPress.
Я уже сформулировал ранее в одной из своих статей эмпирическое правило «территории плагинов:
Если особенность связана с визуальным представлением сайта, то в таком случае она должна быть включена в тему; если же она связана с функциональностью, то тогда она должна быть представлена в виде отдельного плагина.
Довольно простое правило. Люди по-прежнему стараются прописать на уровне кода функциональные фрагменты в своих темах, однако каталоги тем (такие как WordPress.org или ThemeForest) не принимают темы, которые вторгаются на «территорию плагинов». Таким образом, предложение функциональности в темах стало определенной проблемой.
К счастью, есть простое решение, которое не идет вразрез с правилом «территории плагинов».
Введение в библиотеку TGM Plugin Activation
Настройка TGM Plugin Activation
Обратите внимание на функцию tgmpa() с двумя параметрами в самом конце кода. Второй параметр – это переменная $config, которая также является массивом, как и $plugins. Как и следует из ее названия, вы можете настраивать библиотеку TGM Plugin Activation с помощью данного массива. Переменная принимает и свой собственный набор опций:
- id (string) – уникальный id для библиотеки TGM Plugin Activation в вашей теме. Это очень важно: если другие плагины также используют TGM Plugin Activation, разные ID предотвратят возможные конфликты.
- default_path (string) – дефолтный абсолютный путь для плагинов в вашей теме. Когда вы установите его, вы сможете использовать название ZIP-файла в качестве значения параметра source для вашего плагина.
- menu (string) – слаг меню для страницы установки плагинов.
- has_notices (boolean) – если задан в true, администраторские уведомления будут выдаваться для требуемых/рекомендованных плагинов.
- dismissible (boolean) – если задан в true, пользователь может «закрыть» уведомления.
- dismiss_msg (string) – если опция dismissible задана в false, данное сообщение будет показано над администраторским уведомлением.
- is_automatic (boolean) – если задано в true, плагины будут активированы после того, как пользователь согласится их установить.
- message (string) – дополнительный HTML, выводимый перед таблицей плагинов.
- strings (array) – массив, который включает в себя выводимые сообщения. Вы можете задавать их как транслируемые строки. Посмотрите файл example.php, чтобы увидеть полный список всех сообщений.
Заключение
Как вы можете видеть, предложить функциональность в темах WordPress возможно – вы просто должны думать в первую очередь о пользователях, которые могут переключиться с одной темы на другую. Библиотека TGM Plugin Activation предлагает действительно умный способ для этого.
Что вы думаете по поводу данного инструмента? Использовали ли вы его когда-либо, планируете ли вы его использовать в будущем? Делитесь своими мыслями!
Одноразовые ссылки можно использовать в самых разных ситуациях: для того, чтобы предоставить временный доступ к файлу или странице, или для подтверждения регистрации. В этом уроке мы покажем, как сгенерировать и внедрить одноразовые URL адреса.
Создание URL
Предположим, что у нас на сайте есть система аутентификации пользователей. После регистрации мы просим пользователя пройти процедуру верификации email-а. Для создания подобных ссылок можем воспользоваться специальным параметром token. Пример подобной ссылки:
Http://example.com/activate?token=ee97780...
Без базы данных тут нам не обойтись, поэтому давайте посмотрим на таблицу, с которой будем работать.
CREATE TABLE pending_users (token CHAR(40) NOT NULL, username VARCHAR(45) NOT NULL, tstamp INTEGER UNSIGNED NOT NULL, PRIMARY KEY(token));
В таблице будем хранить 3 поля: токен, имя пользователя и время. Для генерации токена мы воспользуемся функцией sha1(), которая выдаёт строку из 40 символов. Поле tstamp будет хранить время генерации токена для того, чтобы мы могли отследить ссылки с истёкшим сроком.
Существует множество способов генерации токена, однако в этом уроке мы воспользуемся функциями uniqid() и sha1(). Независимо от способа генерации токена, убедитесь что генерируемые значения будут разными и вероятность появления дубликатов минимальна.
$token = sha1(uniqid($username, true));
В качестве параметра функция uniqid() принимает строку, а на выходе даёт уникальный идентификатор, основанный на переданном аргументе и текущем времени. Также, в качестве второго аргумента, данная функция принимает булево значение, которое даст сигнал uniqid прибавить несколько дополнительных символов для увеличения вероятности уникальности значения. Функция sha1 принимает уникальный идентификатор и создаёт хэш.
После работы данных двух функций, у нас будет уникальный токен, который можем использовать для генерации url адресов. Теперь нам нужно занести его в базу:
$query = $db->prepare("INSERT INTO pending_users (username, token, tstamp) VALUES (?, ?, ?)"); $query->execute(array($username, $token, $_SERVER["REQUEST_TIME"]));
Для того чтобы мы знали, какого пользователя следует активировать, в таблицу будем записывать и логин пользователя. В примере, более адаптированном для реального сайта, можете воспользоваться ID пользователя.
Теперь, когда у нас есть вся необходимая информация, можем создать временный url адрес:
$url = "http://example.com/activate.php?token=$token";
$message = << Теперь нам нужен скрипт, благодаря которому мы будем осуществлять проверку. Всё что нам нужно сделать, это сравнить токен из url адреса и токен из базы. Если такой имеется, и время его жизни не истекло, то всё ОК. // получаем токен
if (isset($_GET["token"]) && preg_match("/^{40}$/i", $_GET["token"])) {
$token = $_GET["token"];
}
else {
throw new Exception("токен не валиден.");
}
// проверяем токен
$query = $db->prepare("SELECT username, tstamp FROM pending_users WHERE token = ?");
$query->execute(array($token));
$row = $query->fetch(PDO::FETCH_ASSOC);
$query->closeCursor();
if ($row) {
extract($row);
}
else {
throw new Exception("токен не валиден.");
}
// активируем пользовательский аккаунт
// ...
// удаляем токен из базы
$query = $db->prepare("DELETE FROM pending_users WHERE username = ? AND token = ? AND tstamp = ?",);
$query->execute(array($username,
$token,
$tstamp)); Также нам нужно предусмотреть проверку токенов, время жизни которых истекло: // 1 день в секундах = 60 секунд * 60 минут * 24 часа
$delta = 86400;
// проверка
if ($_SERVER["REQUEST_TIME"] - $tstamp > $delta) {
throw new Exception("время жизни токена истекло.");
}
// активируем пользовательский аккаунт
// ... Таким образом, у нас будут осуществляться две проверки: одна на валидность токена, другая на время его существования. Данный метод можно применить не только для активации учётных записей пользователей, но и в других нуждах: к примеру, для предоставления однократного или временного доступа к какому-то ресурсу или услуге. Вдобавок ко всему этому, вы можете создать скрипт, который будет удалять токены, которыми ни разу не пользовались. Данный скрипт можно запускать самим время от времени или применить для этого cron. Регистрирует функцию, которая будет срабатывать во время активации плагина. Эта функция прикрепляет указанную 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. Ничего не возвращает. Название функции обратного вызова. Для классов используйте массив: array($this, "название_функции"); . Функция получит логическую переменную $network_wide - активируется ли плагин для всей сети сайтов, при мультисайте. Предположим у нас есть функция my_plugin_activate() в основном файле плагина: wp-content/plugins/myplugin/myplugin.php , тогда для запуска этой функции во время активации плагина используйте такой код: Register_activation_hook(__FILE__, "my_plugin_activate");
function my_plugin_activate() {
// Код активации...
}
Если плагин использует PHP класс, код активации добавляется так: Register_activation_hook(__FILE__, array("My_Plugin", "install"));
class My_Plugin {
static function install() {
// Не создавайте здесь никакого вывода...
}
}
Если класс, который содержит функцию активации находится в отдельном файле, то регистрируйте функцию активации так: Include_once __DIR__ . "/class-My_Plugin.php";
register_activation_hook(__FILE__, array("My_Plugin", "on_activate_function"));
Если вы находитесь внутри __construct() . Важно, __FILE__ должен «смотреть» на главный файл плагина: Register_activation_hook(__FILE__, array($this, "YOUR_METHOD_NAME"));
После активации плагина срабатывают только два хука: 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");
Небольшой плагин, демонстрирующий как нужно использовать функцию:
/*
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!";
}
Позволяет использовать одну установку WordPress для нескольких сайтов одновременно. При этом каждый сайт получает свои собственные таблицы в базе данных с уникальным префиксом. Таблицы с данными зарегистрированных пользователей общие для всех сайтов сети. Это несомненный плюс и зарегистрировавшись однажды можно получить доступ к нескольким сайтам. Причем на каждом сайте один и тот же аккаунт может иметь разные права. Например, на одном сайте пользователь может быть редактором, а на другом администратором. В обычной установке WordPress страницу регистрации, авторизации и сброса пароля выводит файл wp-login.php . В режиме 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) на основном домене (сайте) сети. Тем не менее, можно создавать страницы регистрации для каждого сайта сети, даже если у них и темы. Мы будем рассматривать случай, когда на всех сайтах сети используется одна тема, но на каждом из них есть страница регистрации. Сайты различаются языком (английский и русский), поэтому страница регистрации будет выводиться на «родном» языке сайта. В случае, если сайты используют разные темы, все будет зависеть от того, какие именно это темы, подойдет ли им одинаковая верстка (отличная ситуация, которая может подтолкнуть вас к унификации всех своих тем) или стоит прорабатывать страницы индивидуально. 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 содержит большое количество функций и кода. Чтобы увидеть картину в целом можно воспользоваться сворачиванием кода. Как правило, по-английски это называется «code folding». В самом начале файла с 1 по 80 строчку (в версии 4.1.1) производятся различные проверки и вывод «старта» страницы с помощью get_header() . Далее объявляются множество методов и перед тем, как мы начнем работать с ними, стоит разобраться что делает каждая функция. Внутри многих из них часто используются другие функции с префиксом wpmu_ , все они объявляются в файле wp-includes/ms-functions.php . Этот раздел тяжело понять не видя код самостоятельно. Ниже небольшое описание основных функций на случай, если у вас возникнут затруднения. В самом низу файла wp-signup.php (со строчки 646 в версии 4.1.1) основная логика работы страницы регистрации, которая использует все выше описанные методы. Эта часть кода не вынесена в функцию. В конце вызывается get_footer() . Далее будет описана процедура копирования 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 . В самом конце удалим два лишних закрывающих Проверка
Итог
Как это работает
Правила использования
Заметка про область переменных
Возвращает
Использование
register_activation_hook($file, $function);
$file(строка) (обязательный)
Путь до главного php файла плагина включая название самого плагина. Обычно используется волшебная константа PHP __FILE__ .
$function(строка/массив/лямбда) (обязательный)
Примеры
#1. Запуск функции при активации плагина
#2. Запуск метода класса
#3. Запуск метода класса из отдельного файла
#4. Запуск метода класса из самого класса
#5 Делаем что-либо сразу после активации плагина
#6 Еще демонстрация использования функции
Основной сайт сети
Альтернатива functions.php
Порядок в файлах
Страница регистрации
Редирект на нужную страницу регистрации
Функционал wp-signup.php
Копируем функционал wp-signup.php