Создание плагина для WordPress. Часть 2.
В предыдущем уроке мы создали фундамент для будущего плагина, который распознает система WordPress. Сегодня мы займемся непосредственно изменением базового функционала системы.
Поможет нам в этом система «хуков» (hooks), «событий» (actions) и фильтров (filters). Эти три понятия и есть основа каждого плагина для WordPress.
Hooks
В WordPress есть два типа хуков:
- Action hook: помечает место в коде, которое выполняет определенное действие, например, необходимо внести какие-либо данные и сохранить в базе.
- Filter hook: помечает фильтр, который будет изменять какое-либо значение (переменную), так что в дальнейшем код будет использовать модифицированное значение.
Actions
Работа с событиями (actions)
Общая логика управления событиями в WordPress проста:
- Пометить место, где действие должно выполниться с помощью хука (action hook) с необходимыми параметрами.
- Создать функцию, которая будет выполнять нужные действия, используя параметры переданные хуком.
- Зарегистрировать событие, которое будет выполняться при срабатывании хука, с определенным приоритетом.
- Когда WordPress загружает страницу и находит hook, система выполнит все функции, которые зарегистрированы на этот хук.
Для выполнения первого пункта система предоставляет функцию ‘do_action’:
do_action($tag, $arg_1, $arg_2, ... , $arg_n);
Она принимает следующие аргументы: $tag – название “хука”, $arg_1, $arg_2, … , $arg_n – параметры, с которыми будет вызвана функция. Аргументов может быть любое количество, либо 0.
Система сама по себе имеет много уже определенных хуков:
do_action( 'init' );
Это очень простой пример без дополнительных аргументов. Данных хук срабатывает, когда большая часть системы уже настроена и пришло время создавать собственные объекты, рубрики, посты и т.п.
do_action('save_post', $post_id, $post);
В этом примере хук срабатывает при сохранении записи с двумя аргументами post_id — идентификатор записи и post — сама запись.
Создание хуков доступно любому разработчику для создания собственного плагина (или темы). Благодаря этому мы имеем мощный инструмент для управления поведением системы.
do_action( 'my_truly_custom_hook' );
Когда мы создали хук и написали функцию, нам необходимо зарегистрировать функцию с помощью «add_action»
add_action($tag, $function_to_add, $priority, $accepted_args_number);
Функция ‘add_action’ принимает два обязательных параметра : $tag: название соответствующего хука и $function_to_add: имя функции, которую необходимо вызвать. Другие два параметра дополнительные: $priority: целочисленная переменная, которая определяет порядок выполнения функции (по-умолчанию — 10), $accepted_args_number: количество аргументов, которое принимает функция (по-умолчанию — 1).
Рассмотрим пример, чтобы понять весь процесс. Допустим, мы хотим добавить небольшое уведомление внизу нашего сайта. Мы можем использовать хук ‘wp_footer’ для этого, потому что он является обязательной частью кода, который использует каждая тема.
function msp_helloworld_footer_notice(){ echo "<div id='msp-helloworld-notice'>Hello, I'm your custom notice</div>"; } add_action('wp_footer', 'msp_helloworld_footer_notice');
В этом примере мы создали функцию, которая просто выводит разметку для оповещения и зарегистрировали её в ‘wp_footer’. Как только мы добавим этот код в файл нашего плагина (см. предыдущий урок) мы увидим результат на странице:
Работа с фильтрами (filters)
Фильтры работают по той же схеме, что и события. Но фильтры не просто выполняют определенный кусок кода, они изменяют значения, переданные им хуком. Это означает, что каждый фильтр имеет связанное с ним значение (переменную), с которым он работает.
Функция-фильтр будет принимать это значение и преобразовывать его для дальнейшего использования. Хуки для фильтров немного отличаются от хуков для событий (action hooks).
apply_filters($tag, $value_to_filter, $arg_1, $arg_2, ... , $arg_n);
Функция ‘apply_filter’ создает хук для фильтра с именем $tag и обязательным параметром $value_to_filter (он может быть пустым, но должен быть объявлен). Остальные аргументы необязательны работают так же как и для событий.
filter_function($value_to_filter, $arg_1, $arg_2, ... , $arg_n){ //фильтр return $value_to_filter; //значение необходимо вернуть }
Это «скелет» фильтра, который демонстрирует, что фильтр должен:
- принимать хотя бы 1 аргумент;
- возвращать модифицированное значение.
add_filter($tag, $function_to_add, $priority, $accepted_args);
Функция ‘add_filter’ регистрирует функцию с названием, содержащимся в $function_to_add для хука $tag. Остальные аргументы — $priority и $accepted_args — работают так же как и у хуков для событий.
Рассмотрим пример: обычная для плагина задача — добавить что-нибудь в конец поста. Если подробнее рассмотреть функцию ‘the_content’, которая используется для вывода содержимого записи, мы найдем такой хук:
$content = apply_filters('the_content', $content);
Используя его мы можем легко добавить что-либо в конец поста.
function msp_helloworld_post_footer($content) { $content .= "<div class='msp-helloworld-post-footer'><p>Hello, I'm your custom post footer</p></div>"; return $content; } add_filter('the_content', 'msp_helloworld_post_footer', 100);
Обратите внимание, что мы используем большое число для приоритета, что убедиться, что до выполнения ‘msp_helloworld_post_footer’ все стандартные фильтры отработают. После включения кода в наш плагин мы увидим результат:
Как найти хук
Теперь нам понятно, что для выполнения определенных действий, нам необходимо знать о существующих хуках.
«Кодекс» WordPress предоставляет списки хуков для фильтров и событий Action Reference и Filter Reference.
Дополнительные действия с хуками
Так же как и добавить, хук можно удалить, используя похожий синтаксис.
Удалить события можно так:
remove_action($tag, $function_to_remove, $priority, $accepted_args); remove_all_actions($tag, $priority);
Как вы догадались, ‘remove_action’ удаляет определенное событие, зарегистрированное для данного хука (необходимо правильно указать приоритет и количество аргументов, так как было указано при регистрации), и ‘remove_all_actions’ помогает удалить все события, зарегистрированные для хука (если приоритет опущен, функция удалит все события).
Фильтры можно удалять так же:
remove_filter($tag, $function_to_remove, $priority, $accepted_args); remove_all_filters($tag, $priority);
API для плагинов в WordPress также предоставляет функции для проверки зарегистрирована ли функция для данного хука:
has_action($tag, $function_to_check); has_filter($tag, $function_to_check);
Обе функции проверяют зарегистрирована ли данная функция для хука и возвращают true в случае успеха, иначе flase. Внутри функции у нас есть возможность проверить, что хук вызвал её:
if('hook_to_check_name' === current_filter()){}
Несмотря на название ‘current_filter’ работает не только с фильтрами но и с событиями.
Нетривиальный пример
Оживим «скелет» нашего плагина, который мы подготовили в прошлом уроке.
Заполним файл ‘core.php’ (главная часть нашего плагина, в которой сосредоточена основная часть функций) кодом, который решает задачу, которая реально может возникнуть в ходе работы. Для её решения мы будем использовать actions и filters.
Пусть ваш WordPress сайт принимает посты разных авторов от гостей, но не позволяет создавать аккаунты. Это значит, что пользователь, который опубликовал пост и реальный автор — разные люди и нам необходимо убедиться, что автор будет указан в посте. Мы можем сделать это с помощью таксономии.
Создадим собственную таксономию для обработки имя автора и его короткой биографии. Мы сможем использовать имя автора как другие термины таксономии (теги, например) в посте. Код:
/** регистрация фильтров и событий **/ function msp_helloworld_init(){ add_action('init', 'msp_helloworld_taxonomies'); add_filter('the_content', 'msp_helloworld_author_block_filter'); add_filter('post_class', 'msp_helloworld_post_class'); } add_action('plugins_loaded', 'msp_helloworld_init'); /** taxonomy **/ function msp_helloworld_taxonomies(){ $args = array( 'labels' => array( 'name' => 'Guest authors', 'singular_name' => 'Guest author' ), 'show_in_nav_menus' => false ); register_taxonomy('gauthor', array('post'), $args); } /** разметка блока автора **/ function msp_helloworld_author_block(){ global $post; $author_terms = wp_get_object_terms($post->ID, 'gauthor'); if(empty($author_terms)) return; $name = stripslashes($author_terms[0]->name); $url = esc_url(get_term_link($author_terms[0])); $desc = wp_filter_post_kses($author_terms[0]->description); $out = "<div class='gauthor-info'>"; $out .= "<h5>This is a guest post by <a href='{$url}'>{$name}</a></h5>"; $out .= "<div class='gauthor-desc'>{$desc}</div></div>"; return $out; } /** добавить разметку в конец поста **/ function msp_helloworld_author_block_filter($content){ if(is_single()) $content .= msp_helloworld_author_block(); return $content; } /** добавить CSS class к посту **/ function msp_helloworld_post_class($post_class){ global $post; $author_terms = wp_get_object_terms($post->ID, 'gauthor'); if(!empty($author_terms)){ $post_class[] = 'gauthor'; } return $post_class; }
Как видите, мы создали функцию для регистрации собственной таксономии и привязали её к хуку ‘init’. После мы создали шаблон, отвечающий за отображение блока автора, используя функцию WordPress ‘wp_get_object_terms’. После мы вставили блок с информацией об авторе в конец поста с помощью фильтра ‘the_content’. И, наконец, мы добавили собственный CSS класс. Результат работы:
Заключение
Actions и filters — самая важная часть любой разработки для WordPress. Теперь, когда вы понимаете их логику и поведение, вы можете экспериментировать самостоятельно или перейти к следующей части.
Интересно, полезно! Спасибо! Но в последнем примере мало комментариев, приходится код разбирать. А предыдущие уроки легко, быстро и очень понятно!