Плагины
Плагин добавляет сайту возможности, не трогая ядро: свои типы записей и блоки, страницы в админке,
вывод на сайте, обработку заявок. Плагин — это папка в plugins/; включают и выключают его в разделе «Плагины».
Плагин за 10 минут
php artisan cms:make-plugin otzyvy --name="Отзывы" --author="Студия ARGELIT"
Появится папка plugins/otzyvy с готовым к включению плагином. Включите его в «Плагины» и дописывайте код
в src/Otzyvy.php. Полный рабочий пример — плагин «Отзывы», а плагин
«Объявление на сайте» (plugins/announcement) показывает страницу настроек в админке.
Из чего состоит плагин
plugins/
└── otzyvy/ ← папка = имя плагина: латиница, цифры, «-», «_» (нельзя «cms» и «theme»)
├── plugin.json ← описание (обязательно)
├── plugin.php ← код, который подключается на каждом запросе, пока плагин включён (обязательно)
├── src/ ← классы плагина (подключаются сами, см. «autoload»)
├── views/ ← шаблоны Blade: view('otzyvy::settings')
├── assets/ ← стили, скрипты, картинки: plugin_asset('otzyvy', 'otzyvy.css')
├── routes/web.php ← свои адреса на сайте
├── database/migrations/← свои таблицы
└── uninstall.php ← уборка при удалении плагина
plugin.json
{
"name": "Отзывы",
"description": "Отзывы клиентов с оценкой и блок для страниц.",
"version": "1.0.0",
"author": "Студия ARGELIT",
"uri": "https://argelit.com",
"requires_cms": "0.13",
"requires_php": "8.3",
"autoload": { "Studio\\Otzyvy\\": "src" }
}
| Поле | Зачем |
|---|---|
name, description, version, author, uri |
показываются в списке плагинов |
requires_cms |
минимальная версия CMS; на более старой плагин нельзя установить и включить |
requires_php |
минимальная версия PHP |
autoload |
пространство имён классов → папка (как PSR-4 в Composer): класс Studio\Otzyvy\Reviews — файл src/Reviews.php |
sandbox |
false — плагин не показывается в демо-сайтах посетителей (режим CMS_SANDBOX); по умолчанию — показывается |
plugin.php
Подключается на каждом запросе, пока плагин включён. Внутри доступна переменная $plugin — описание плагина
($plugin->slug — папка, $plugin->name, $plugin->version, $plugin->path). Лучшая практика — держать здесь только
подписки на события, а работу — в классах:
<?php
use Studio\Otzyvy\Reviews;
(new Reviews($plugin))->register();
Не объявляйте в plugin.php функции (function my_func() {}): файл может подключаться повторно, и PHP упадёт
с ошибкой «функция уже объявлена». Используйте классы или замыкания.
Включение, отключение, удаление
register_activation_hook($plugin, fn () => update_option('otzyvy_version', $plugin->version));
register_deactivation_hook($plugin, fn () => cache()->forget('otzyvy_list'));
- При включении CMS подключает классы, выполняет миграции из
database/migrations/и вызывает событиеactivate_{папка}. Если на любом шаге ошибка — плагин остаётся выключенным, а текст ошибки показывается в «Плагинах». - При отключении — событие
deactivate_{папка}; настройки и таблицы плагина остаются. - При удалении (кнопка «Удалить» у выключенного плагина) выполняется
uninstall.php— здесь плагин удаляет свои настройки, таблицы и записи, затем удаляется папка:
<?php // uninstall.php
use Illuminate\Support\Facades\Schema;
Schema::dropIfExists('otzyvy_votes');
delete_option('otzyvy_version');
Шаблоны, стили, скрипты
- Шаблоны из
views/доступны какпапка::имя:view('otzyvy::blocks.list')— файлviews/blocks/list.blade.php. - Файлы из
assets/отдаются по адресу/plugin-assets/{папка}/{файл}(только у включённых плагинов):
add_action('site_head', function () {
echo '<link rel="stylesheet" href="'.e(plugin_asset('otzyvy', 'otzyvy.css')).'">';
});
add_action('site_footer', function () {
echo '<script src="'.e(plugin_asset('otzyvy', 'otzyvy.js')).'" defer></script>';
});
К адресу добавляется время изменения файла — после правки браузер сразу возьмёт новую версию.
Вывод на сайте
| Куда | Как |
|---|---|
в <head> |
событие site_head($context) |
сразу после <body> (полоса объявления, счётчики) |
событие site_body_open($context) |
перед </body> |
событие site_footer($context) |
| в текст записей | фильтр the_content($html, $post) |
| свой блок, который редактор ставит куда угодно | register_block_type() — см. Блоки |
| в шаблон темы | функция вашего класса, которую вызывает тема, или своё событие |
$context — что открыто на сайте (см. Темы).
Страница в админке
add_admin_page('otzyvy', 'Настройки отзывов', [Settings::class, 'page'], [
'parent' => 'settings', // подпункт раздела «Настройки»; без parent — свой пункт в меню
'menu_title' => 'Отзывы',
'capability' => 'manage_options',
]);
| Параметр | По умолчанию | Что значит |
|---|---|---|
menu_title |
заголовок страницы | текст в меню |
capability |
manage_options |
какое право нужно, чтобы открыть страницу |
parent |
— | раздел, в котором страница будет подпунктом: settings, tools, plugins, appearance, users, dashboard или раздел типа записей по его адресу в админке (posts, pages, reviews…) |
icon |
plug |
значок, если страница — свой пункт меню |
position |
100 | место в меню |
show_in_menu |
true |
false — страница без пункта меню (открывается по ссылке) |
Страница открывается по адресу /admin/page/otzyvy (в коде — admin_page_url('otzyvy')) и на GET, и на POST.
Функция страницы получает Illuminate\Http\Request и возвращает шаблон (его содержимое встанет в админку с заголовком
и уведомлениями) или ответ — например, перенаправление после сохранения:
public static function page(Request $request): View|RedirectResponse
{
if (! $request->isMethod('post')) {
return view('otzyvy::settings', ['perPage' => get_option('otzyvy_per_page', 3)]);
}
$data = $request->validate(['per_page' => ['required', 'integer', 'between:1,24']]);
update_option('otzyvy_per_page', (int) $data['per_page']);
return redirect(admin_page_url('otzyvy'))->with('status', 'Сохранено.');
}
В шаблоне — обычная форма на admin_page_url('otzyvy') с @csrf; ошибки и сообщение status админка покажет сама.
Ссылку «Настройки» под названием плагина в списке плагинов добавляет фильтр:
add_filter('plugin_action_links_otzyvy', fn (array $links) => ['Настройки' => admin_page_url('otzyvy')] + $links);
Свои адреса на сайте
routes/web.php подключается раньше адресов ядра, с обычной защитой Laravel (сессии, CSRF):
<?php
use Illuminate\Support\Facades\Route;
use Studio\Otzyvy\Http\VoteController;
Route::post('otzyvy/{review}/vote', VoteController::class)->middleware('throttle:10,1')->name('otzyvy.vote');
Не занимайте адреса, которые могут совпасть с записями сайта: берите префикс плагина (otzyvy/…).
Свои таблицы
Миграции Laravel в database/migrations/ выполняются при включении плагина, а для уже включённых —
при обновлении CMS и команде php artisan migrate. Таблицы называйте с префиксом плагина:
return new class extends Migration {
public function up(): void
{
Schema::create('otzyvy_votes', function (Blueprint $table) {
$table->id();
$table->foreignId('post_id')->constrained('posts')->cascadeOnDelete();
$table->string('ip', 45);
$table->timestamps();
});
}
};
Типы записей, поля в редакторе, блоки, формы
- Свой тип записей (отзывы, услуги, вакансии), таксономии, метаполя и блоки полей в редакторе — Контент.
- Свои блоки для редактора — Блоки.
- Заявки с форм: событие
form_submitted($form, $entry), фильтрыform_fields,form_recipients— Контент.
Если плагин сломался
Если плагин падает с ошибкой на любом запросе, CMS отключает его сама, сохраняет текст ошибки (с файлом и строкой) и показывает его в «Плагинах» — остальной сайт продолжает работать. После исправления плагин включают снова.
Публикация
Плагин распространяется как zip-архив его папки: внутри — папка otzyvy/ с plugin.json
(или plugin.json прямо в корне архива — тогда папка получит имя архива: otzyvy-1.2.0.zip → otzyvy).
Ставят его в «Плагины → Добавить плагин». Новая версия ставится так же, с галочкой «Заменить установленную версию»:
включённый плагин остаётся включённым, его новые миграции выполняются сразу.
Перед публикацией:
- поднимите
versionи проверьтеrequires_cms/requires_php; - проверьте, что
uninstall.phpубирает всё, что создаёт плагин; - не кладите в архив
.git,node_modules, файлы с паролями.
На сайтах с CMS_FILE_MODS=false в .env (например, на демо) плагины из админки не устанавливаются — только копированием папки.