Как сделать WordPress-плагин расширяемым

Представьте, что вы - разработчик плагина. Что вы сделаете, если пользователь попросит реализовать в плагине определённую функциональность? Но если она востребована только некоторыми пользователями, тогда её добавление непрактично.

Оптимальный вариант — сделать плагин расширяемым на уровне кода, чтобы другие могли улучшать или изменять его под свои нужды. В статье рассказывается о том, как это реализовать на практике.

Что делает плагин расширяемым?

Применение этого принципа к WordPress означает, что плагин является расширяемым, если он включает в себя средства, позволяющие другим людям изменять его поведение. Но только на уровне плагинов.

Типичный пример плагина

Допустим что, есть плагин, генерирующий виджет боковой панели, в котором отображаются заголовки трёх последних опубликованных постов. В его основе лежит функция, которая оборачивает заголовки этих трёх постов в тэги:

function get_some_post_titles() {
$args = array(
'posts_per_page' => 3,
);
$posts = get_posts( $args );
$output = '';
foreach ( $posts as $post ) {
$output .= '' . $post->post_title . '';
}
$output .= '';
return $output;
}

Этот код работает и выполняет поставленную задачу, но он не расширяемый. Почему? Потому что функция определяется сама по себе, нет никакого способа изменить её поведение без непосредственного изменения кода.

А если нужно вывести более трёх последних постов. Или, например, добавить ссылки к заголовкам публикаций? Пользователь ограничен тем, как работает плагин и не может ничего изменить.

Включение сотни настроек – неверный путь

Есть несколько способов улучшить приведенный выше плагин. Например, добавление целой кучи настроек. Но даже они не смогут удовлетворить все требования, предъявляемые пользователями к плагину.

Если пользователь хочет реализовать один из следующих:

  • отображать продукты из WooCommerce или посты только из определённой категории;
  • отображать элементы в карусели, формируемой другим плагином, вместо простого списка;
  • осуществлять запрос к базе данных, а затем использовать его результаты, выведенные в виде списка.

Если добавить сотню настроек в создаваемый виджет, тогда можно т реализовать некоторые из этих сценариев. Но что, если пользователь захочет отображать только те продукты WooCommerce, которые есть в наличии? Виджету вновь потребуются дополнительные настройки.

Так как же решить эту проблему? Нужно сделать плагин расширяемым.

Добавление хуков для расширения плагина

В приведенном выше коде видно, что функция отвечает за несколько операций:

  • Получает посты, используя get_posts.
  • Генерирует список заголовков постов.
  • Возвращает сгенерированный список.

Чтобы сделать плагин расширяемым, нужно добавить хуки, чтобы открыть их для других разработчиков.

Области для добавления хуков:

  • вокруг и внутри основных процессов;
  • при выводе сгенерированного HTML;
  • для изменения постов или запросов к базе данных;
  • перед возвращением значений функции.

Типичный пример расширяемого плагина

Следуя этим правилам, можно добавить следующие фильтры, чтобы сделать плагин расширяемым:

  • добавить myplugin_get_posts_args для изменения аргументов get_posts;
  • добавить myplugin_get_posts для перезаписи результатов get_posts;
  • добавить myplugin_list_item для настройки генерации элементов списка;
  • добавить myplugin_get_some_post_titles для перезаписи возвращаемого списка.

Код со всеми добавленными хуками:

function get_some_post_titles() {
$args = array(
'posts_per_page' => 3,
);
// Позволить другим людям изменять аргументы
$posts = get_posts( apply_filters( 'myplugin_get_posts_args', $args ) );
// Позволить другим изменять массив постов, которые будут выводиться
$posts = apply_filters( 'myplugin_get_posts', $posts, $args );
$output = '';
foreach ( $posts as $post ) {
// Позволить другим людям изменять элементы списка
$output .= '' . apply_filters( 'myplugin_list_item', $post->post_title, $post ) . '';
}
$output .= '';
// Позволить другим людям изменять выводимый список
return apply_filters( 'myplugin_get_some_post_titles', $output, $args );
}

Скачать исходный код.

Я добавляю сюда много хуков, что может показаться непрактичным. Но он иллюстрирует мои слова: «При добавлении всего четырёх хуков, другие разработчики смогут настраивать поведение плагина как им угодно».

Пространства имён и хуков

Прежде чем продолжать, обратим внимание на две важных особенности хуков, которые мы реализовали:

  • Мы обозначаем пространства имён хуков с помощью myplugin_.
    Это гарантирует, что имя хука не вступит в конфликт с хуком другого плагина. Если вызовется другой хук с тем же именем, это может привести к нежелательным последствиям.
  • Мы передаём ссылку на аргументы $args вовсе контексты хука.
    Если другие разработчики используют этот фильтр для изменения кода, они смогут применить $args как ссылку, чтобы понять, зачем вызывается хук.

Эффекты от хуков

Помните уникальные сценарии, о которых я говорил выше? Пробежимся по ним ещё раз и посмотрим, как наши хуки сделали их возможными:

  • Если пользователь хочет отобразить продукты из WooCommerce или посты из определённой категории - он может либо использовать фильтрmyplugin_get_posts_args, чтобы добавить свои аргументы, когда плагин запрашивает посты. А также использовать myplugin_get_posts, чтобы полностью перезаписать список постов собственным.
  • Если пользователь хочет отобразить элементы в карусели, сформированной другим плагином, вместо простого списка, он может перезаписать весь вывод функции с помощью myplugin_get_some_post_titles, и вывести карусель оттуда.
  • Если пользователь хочет выполнить собственный запрос к базе данных, а затем использовать посты из этого запроса в списке, он может применить myplugin_get_posts, чтобы использовать свой запрос и изменить массив постов.

Быстрый пример использования фильтров

Разработчики могут использовать add_filter, чтобы привязаться к нашим фильтрам (или использовать add_action для действий).

Рассмотрим в качестве примера первый сценарий. Разработчик может использовать приведенный ниже код для отображения продуктов из WooCommerce, применив фильтр myplugin_get_posts_args, который мы создали:

add_filter( 'myplugin_get_posts_args', 'show_only_woocommerce_products' );
function show_only_woocommerce_products( $args ) {
$args['post_type'] = 'product';
return $args;
}

Мы также можем использовать хуки действий

Кроме apply_filters также можно использовать do_action, чтобы сделать код расширяемым. Разница между ними в том, что первый позволяет изменить переменную функцию, а второй - выполнять дополнительные действия в разных частях кода.

При использовании действий мы раскрываем логику плагина другим разработчикам и позволяем им выполнять другие действия наряду с вашей логикой.

Например, расширяемый плагин резервного копирования можно «научить» загружать созданный файл на сторонний сервис, такой как Dropbox.

Почему нужно заботиться о расширяемости своего плагина?

Ещё несколько причин, почему нужно разрешать другим людям изменять поведение вашего плагина.

Это открывает плагину большие возможности настройки

Велика вероятность того, что ваш плагин не будет удовлетворять всех пользователей. Открытие плагина для изменений в ключевых областях поведения может творить чудеса.

Это помогает людям вносить изменения без редактирования кода плагина

Другим разработчикам не придётся изменять файлы плагина. Это огромное преимущество, поскольку редактирование кода плагина – плохая практика. Если плагин обновится, все внесенные в него изменения будут потеряны.

Если мы добавляем собственные хуки для использования другими разработчиками, тогда модификации плагина могут быть размещены в другом месте. Например, в другом плагине. При этом исходный плагин не будет затронут, а после обновления все модификации останутся неизменными.

Заключение

Взгляните на такие плагины, как WooCommerce, Easy Digital Downloads и ACF. Эти плагины расширяемые. Вы легко можете убедиться в этом, поскольку многие другие WordPress-плагины добавляют к ним различную функциональность. Они также предоставляют широкий набор хуков действий и фильтров, которые изменяют различные аспекты плагинов.

Советы, как сделать плагин расширяемым:

  • Добавьте хуки в следующие места:
    • вокруг и внутри основных процессов;
    • при построении HTML-вывода;
    • для изменения постов или запросов к базе данных;
    • перед возвращением значений функций.
  • Используйте префиксы пространства имён в ваших хуках, чтобы избежать конфликтов именования.
  • Старайтесь передавать другие переменные, связанные с хуком, чтобы другие люди получали контекст того, что происходит в хуке.
  • Не забудьте документировать хуки плагина, чтобы другие смогли научиться их использовать.

Как сделать ваш WordPress-плагин расширяемым - код примеров из этой статьи.

Сергей Бензенкоавтор-переводчик статьи «How To Make A WordPress Plugin Extensible»