Создание плагина для WordPress. Часть 2.

13-01-22 WordPress PHP, WordPress 1

В предыдущем уроке мы создали фундамент для будущего плагина, который распознает система WordPress. Сегодня мы займемся непосредственно изменением базового функционала системы.

Поможет нам в этом система «хуков» (hooks), «событий» (actions) и фильтров (filters). Эти три понятия и есть основа каждого плагина для WordPress.

Hooks

В WordPress есть два типа хуков:

  • Action hook: помечает место в коде, которое выполняет определенное действие, например, необходимо внести какие-либо данные и сохранить в базе.
  • Filter hook: помечает фильтр, который будет изменять какое-либо значение (переменную), так что в дальнейшем код будет использовать модифицированное значение.

Actions

Работа с событиями (actions)

Общая логика управления событиями в WordPress проста:

  1. Пометить место, где действие должно выполниться с помощью хука (action hook) с необходимыми параметрами.
  2. Создать функцию, которая будет выполнять нужные действия, используя параметры переданные хуком.
  3. Зарегистрировать событие, которое будет выполняться при срабатывании хука, с определенным приоритетом.
  4. Когда 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’. Как только мы добавим этот код в файл нашего плагина (см. предыдущий урок) мы увидим результат на странице:

Создание плагина для WordPress
Оповещение плагина WordPress

Работа с фильтрами (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. принимать хотя бы 1 аргумент;
  2. возвращать модифицированное значение.
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 plugin
WordPress plugin

Как найти хук

Теперь нам понятно, что для выполнения определенных действий, нам необходимо знать о существующих хуках.

«Кодекс» 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 класс. Результат работы:

WordPress плагин
WordPress плагин

Заключение

Actions и filters — самая важная часть любой разработки для WordPress. Теперь, когда вы понимаете их логику и поведение, вы можете экспериментировать самостоятельно или перейти к следующей части.

Хочешь получать статьи на почту?

Подпишись на обновления!
* Ваш email не будет разглашен/продан. Вы сможете отписаться в любое время.

1 Комментарий

  1. Александр says:

    Интересно, полезно! Спасибо! Но в последнем примере мало комментариев, приходится код разбирать. А предыдущие уроки легко, быстро и очень понятно!

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *