Обзор шаблонов для создания плагинов WordPress

Если полистать сайт developer.wordpress.org то можно найти пост который называется  Best Practice (лучшие практики).
В этом посте меня заинтересовал последний пункт там говорится что вместо того чтобы начинать создание каждого нового плагина с нуля  можно воспользоваться заранее сделанными заготовкам и приведен их список.

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

Конечно же я ознакомился со списком приведенных ссылок сразу же приведу их в порядке пригодности.

  1. WP CLI Scaffold
  2. WP Skeleton Plugin
  3. WordPress Plugin Bootstrap
  4. WordPress Plugin Boilerplate

1) WP CLI Scaffold

Очень удобная функция WP CLI, позволяет создать заготовку плагина уже подготовленную для написания phpunit тестов, так же есть интеграция с различными  CI (Continuous Integration) системами, предусмотрен файл с правилами для phpcs, это очень удобно когда нужно придерживаться стиля рекомендованного codex wordpress. Еще есть Grunt файл с помощью которого можно почти моментально создать pot файл для дальнейшего перевода будущего плагина на разные языки мира.
И все ничего больше нет и это даже хорошо что что нам не пытаются диктовать какую то структуру каталогов или возможно отрывки кода. Мы вольны сделать что угодно и для этого у нас есть авто тесты и набор некоторых утилит.

Например если бы я делал какой либо плагин я бы мог создать для него заготовку как то так:

wp scaffold plugin awesome_plugin --plugin_author=petrozavodsky --ci=gitlab --activate

С помощью параметров командной строки wp cli может добавлять различные данные в шапку плагина, так при помощи параметра plugin_author можно указать автора плагина, а параметр —ci помогает выбрать систему CI для вашего новго плагина, так же только что созданный плагин можно активировать сразу после создания если указать —activate.

С остальными параметрами можно ознакомиться на этой странице. Мне кажется что это хороший и удобный инструмент.

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

2) WP Skeleton Plugin

Тут нет никаких инструментов командной строки для развертывания проекта, зато есть поддержка PHPUnit и Behat тестовая среда запускается с помощью Phing (это что то вроде сборщика проектов Ant) и все выгялдит весьма неплохо, но есть и минусы репозиторий в последний раз обновлялся 7 лет назад там до сих пор обозначена поддержка bower который уже дано не поддерживается сообществом и на смену ему пришел npm.

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

3) WordPress Plugin Bootstrap

Репозиторий просто архивирован владельцем, скорее всего по причине того что используемые утилиты морально устарели и больше не поддерживаются . Этот репозиторий так же как и прошлый обновлялся 7 лет назад. В виду того что сейчас он имеет статус read-only  думаю смысла останавливаться на нем на долго нет смысла.

4) WordPress Plugin Boilerplate

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

Вот цитата из README.md:

A standardized, organized, object-oriented foundation for building high-quality WordPress Plugins.

Непонятно что это но, все самые крутые эпитеты собраны в этом предложении.

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

Описание инсталяции

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

Можно подумать что в репозитории есть какая то утилита которая может автоматически поменять название плагина в репозитории, но ничего такого там нет.

Нет интеграции с CI/CD, нет никаких утилит или конфигов, вообще ничего.

В этом репозитории есть только код, переименовывай как хочешь.  Если нужен pot файл, то как нибудь сделай в  README.md упоминаются Poedit, makepot, i18n. Иными словами если пишешь плагин, сделай как нибудь и его интернационализацию, тебе же это зачем то понадобилось

Неопределенность тут во всем например есть метод:

register_deactivation_hook( __FILE__, 'deactivate_plugin_name' );

но одновременно есть и файлик uninstall.php, думаю можно было бы чем то одним обойтись, зачем на столько сильно акцентироваться на деинсталляции плагина, что бы  посильнее деинсталировал что ли:)

Для лучшего понимания что это за проект достаточно посмотреть класс i18n:

class Plugin_Name_i18n {
	public function load_plugin_textdomain() {
		load_plugin_textdomain(
			'plugin-name',
			false,
			dirname( dirname( plugin_basename( __FILE__ ) ) ) . '/languages/'
		);
	}
}

Мы создаем целый класс который не содержит ничего кроме одного метода, в котором просто вызов функции load_plugin_textdomain с уже заданными аргументами. Как можно было бы использовать этот класс в дальнейшем, затрудняюсь ответить, думаю можно было бы обойтись просто методом в основном файле плагина, ну или во всяком случае чем то меньшим чем целый класс.

Но есть и более интересная затея класс Plugin_Name_Loader. Вместо того что бы использовать add_action и add_filter из ядра WordPress предлогается делать так:

$this->loader->add_action( 'plugins_loaded', $plugin_i18n, 'load_plugin_textdomain' );

Просто на хук навешивается метод класса, я даже знаю как еще красивее выглядело:

add_action( 'plugins_loaded', [$plugin_i18n, 'load_plugin_textdomain'] );

Можно сделать так, использовать анонимные функции например:

add_action( 'plugins_loaded', function(){
...
});

Не я конечно понимаю что авторы этого репозитория наверное 19 век застали и может тогда это не казалось плохой идеей, но лямда функции в php 5.3 появились в 2009 году, а первый коммит датируется 2011, то есть могли бы сделать какую то поддержку.

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

// add_action может даже самые обычные функции использовать
// в отличии от этго класса, удобно не правлда ли.
add_action( 'plugins_loaded', 'my_function');

Как например вот это:

add_filter('the_excerpt', 'trim');

через такой лодер реализовать?

Очевидно авторы плагина как то вот так себе это представляли:

class Plugin_Name_trim {

	public function trim( $string_text ) {
		return trim( $string_text );
	}
}

...

private
function set_trim() {
	$plugin_trim = new Plugin_Name_trim();
	$this->loader->add_filter( 'the_excerpt', $plugin_trim, 'trim' );
}

Ну то есть мусор какой то, не представляю при каких обстоятельствах это могло бы быть удобно.

Даже если все вышеописанное не аргумент для вас, как на счет того что add_filter/add_action поддерживает в IDE автодополнение, а эта балалайка нет, придется опечатку часами искать в случае чего.

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

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

Единственное отличие от обычного использования add_filter/add_action в том что все имена вызываемых методов сохраняются в свойства класса.

Вот так вот эти свойства выглядят:

class Plugin_Name_Loader {
	protected $actions;
	protected $filters;

	public function __construct() {
		$this->actions = array();
		$this->filters = array();
	}

...

}

После вызова метода run()  оба эти свойства actions и filters в конечном итоге перебираются циклом и через add_filter/add_action региструются в WordPress. Но вот зачем именно так происходит одному богу известно.

Примерно так же они (функции/методы прикрепленные к хукам) попадают в глобальную переменную и там хранятся (это переменные wp_filter, wp_actions), но происходит это в ядре WordPress.

Можно было бы их отуда извлекать если бы это зачем то понадобилось, так делают некоторые плагины например Debug Bar Actions and Filters Addon.

Плюс ко всему add_filter и add_action предлагает обернуть, а вот do_action и apply_filters  нет, кажется что это как-то не логично.

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

Резюмирую тем что этот лодер это полный отстой.

Какие то странные манипуляции дальше происходят, вот зачем было делать это:

function run_plugin_name() {
	$plugin = new Plugin_Name();
	$plugin->run();
}

run_plugin_name();

Можно было скажем и без функции обойтись, совершенно ничего не изменится:

$plugin = new Plugin_Name();
$plugin->run();

Я бы ещё понял если бы это выглядело как-то так

function run_plugin_name() {

$plugin = new Plugin_Name();
$plugin->run();

}

add_action( 'plugins_loaded', 'run_plugin_name' );

Хотя бы можно было сделать remove_action и наличие функции run_plugin_name было бы этим оправдано, и плагин вызывался бы с понятным приоритетом и не зависли от названия плагина в алфавитном порядке.

public function run() {
   $this->loader->run();
}

Но это только мои выдумки в оригинальном репозитории ничего подобного нет.

Структура плагина сомнительная например этот класс:

/plugin-name/public/class-plugin-name-public.php

Лежит в каталоге public описывает скрипты и стили, так почему бы этому классу не лежать скажем в каталоге includes, тогда бы можно было сказать что в public только статичные файлы, а так ничего определенного об этом каталоге сказать нельзя.

Есть такой же каталог как public с аналогичными файлами только называется admin, и там полное дублирование, думаю стили для панели администраторов вполне могли бы находиться в каталоге public или public/admin от этого бы хуже не стало.

Плюс внутри public еще и какой то странный подкаталог с файлом

public/partials/plugin-name-public-display.php

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

Если это файл шаблонов то почему имя такое plugin-name-public-display.php WordPress Codex кажется такое именование для шаблонов не предполагает.

К примеру WooCommerce хранит шаблоне в каталоге templates а не public/partials/ и названия у них не содержат имени плагина.

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

К слову на WordPress Developer Resources есть пример структуры каталогов , там тоже есть каталоги public и admin что мне не очень то нравится, но внутри них нет никаких каталогов partials и это хорошо.

 Пример структуры каталогов

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

Думаю теперь всем понятно что это не пример правильной структуры и кода плагина.

К счастью в репозитории больше ничего нет, и на этой радостной ноте можно наконец завершить его обзор.

Как я уже говорил ранее, крайне не рекомендую как либо использовать этот код в своей работе.

Этот пост предваряет мою вторую статью (которую я опубликую на днях) о моем же проекте предназначенном для быстрого и правильного старта разработки плагинов для WordPress.

UPD для последнего репозитория есть генератор плагинов, как выяснилось — https://wppb.me/ (но от этого не легче)

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

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