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

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

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

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

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

В идеале нужно это реализовать. Но если функционал запрашивался для очень узкоспециализированного случая, то его добавление было бы непрактичным. Зачем добавлять настройку в плагин, которой будут пользоваться от силы 0,1% всех ваших пользователей.

Вам нужно создавать только те возможности, которые затронут большинство пользователей плагина. На самом деле 80% пользователей работают только с 20% настроек плагина (правило 80/20). Поэтому убедитесь в том, что любая новая функция пользуется высоким спросом, и 80% ваших пользователей выиграют от ее добавления. Только тогда можно будет ее реализовать. Если вы будете создавать отдельную настройку для каждой запрашиваемой функции, то в таком случае ваш плагин быстро станет раздутым и сложным – и никто не будет им пользоваться.

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

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

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

Если говорить в двух словах, то расширяемый плагин означает, что он придерживается принципа «О» в методологии SOLID, которая существует для ООП – принципа open/closed.

Если вы не знакомы с принципом open/closed, то я расскажу, что он означает: это значит, что другим людям не нужно редактировать ваш код, чтобы что-то модифицировать.

Применительно к плагинам WordPress это означает следующее: плагин является расширяемым, когда в нем есть определенные участки, которые позволяют другим пользователям изменять его поведение. Это напоминает то, что уже реализовано в 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;
}

Этот код работает, но он не является в достаточной степени расширяемым.

Почему? Потому что функция прописана без возможности изменения ее поведения. Для корректировки ее поведения придется редактировать ее код.

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

Включение сотен параметров – это не решение

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

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

Что делать, если пользователь захотел выполнить одно из следующих действий:

  • Вывод 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,
  );

  // Let other people modify the arguments.
  $posts = get_posts( apply_filters( 'myplugin_get_posts_args', $args ) );

  // Let other people modify the post array, which will be used for display.
  $posts = apply_filters( 'myplugin_get_posts', $posts, $args );

  $output = '';
  foreach ( $posts as $post ) {

      // Let other people modify the list entry.
      $output .= '' . apply_filters( 'myplugin_list_item', $post->post_title, $post ) . '';
  }
  $output .= '';

  // Let other people modify our output list.
  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. Они также предлагают широкий спектр действий и фильтров, которые помогают изменить разные аспекты функционирования.

Источник: https://www.smashingmagazine.com

Блог про WordPress
Комментарии: 2
  1. Otshelnik-Fm

    Странная статья. Уместилось бы все в 1 абзац — добавьте фильтры и экшены.

    А где же про отмену хуков? Чтобы написать свою замену?
    А где про ООП — когда удобно можно наследовать класс и прочие плюшки?

    Про настройки согласен и удивился что не упомянул он тут как ВП сам устроен — что у него нет сотни настроек именно по этой причине.

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

    А функционал шаблонов? Как у WP-Recall, bbPress и прочих больших плагинов -для кастомизации и расширения самое то.

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

    1. Дмитрий (автор)

      Да, согласен, скорее просто вводная статья на эту тему.

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

Получать новые комментарии по электронной почте.