Разработка кастомного плагина Joomla
Плагины Joomla реагируют на системные события. Перехватывают моменты жизненного цикла: до/после сохранения статьи, при аутентификации, при поиске, при отправке формы. Это самый правильный способ расширить поведение системы без модификации ядра.
Группы плагинов
| Группа | Событие | Применение |
|---|---|---|
| content | onContentBeforeSave, onContentAfterSave | Обработка контента |
| user | onUserLogin, onUserAfterSave | Аутентификация, синхронизация |
| system | onAfterRoute, onBeforeRender | Глобальные перехваты |
| authentication | onUserAuthenticate | Внешние провайдеры входа |
| finder | onFinderIndexItem | Поисковый индекс Smart Search |
| task | onExecuteTask | Планировщик задач (Joomla 4+) |
Структура плагина
plg_content_synccrm/
├── plg_content_synccrm.php # Точка входа (для legacy)
├── plg_content_synccrm.xml # Манифест
├── services/
│ └── provider.php # DI Provider
└── src/
└── Extension/
└── SyncCrmPlugin.php # Основной класс
Манифест
<?xml version="1.0" encoding="utf-8"?>
<extension version="4.0" type="plugin" group="content">
<name>plg_content_synccrm</name>
<author>Your Company</author>
<version>1.0.0</version>
<description>Синхронизация контента с CRM при публикации</description>
<namespace path="src">MyCompany\Plugin\Content\SyncCrm</namespace>
<files>
<filename plugin="plg_content_synccrm">plg_content_synccrm.php</filename>
<folder>services</folder>
<folder>src</folder>
</files>
<config>
<fields name="params">
<fieldset name="basic">
<field name="crm_api_url" type="text" label="URL CRM API" />
<field name="crm_api_key" type="password" label="API Key CRM" />
<field name="sync_types" type="checkboxes" label="Синхронизировать типы">
<option value="article">Статьи</option>
<option value="product">Товары</option>
</field>
</fieldset>
</fields>
</config>
</extension>
DI Provider
// services/provider.php
use Joomla\CMS\Extension\PluginInterface;
use Joomla\DI\Container;
use MyCompany\Plugin\Content\SyncCrm\Extension\SyncCrmPlugin;
return new class implements \Joomla\DI\ServiceProviderInterface {
public function register(Container $container): void {
$container->set(PluginInterface::class, function (Container $container) {
$dispatcher = $container->get(\Joomla\Event\DispatcherInterface::class);
$plugin = new SyncCrmPlugin($dispatcher, []);
$plugin->setApplication($container->get(\Joomla\CMS\Application\CMSApplicationInterface::class));
return $plugin;
});
}
};
Основной класс плагина
// src/Extension/SyncCrmPlugin.php
namespace MyCompany\Plugin\Content\SyncCrm\Extension;
use Joomla\CMS\Plugin\CMSPlugin;
use Joomla\Event\Event;
use Joomla\Event\SubscriberInterface;
class SyncCrmPlugin extends CMSPlugin implements SubscriberInterface {
public static function getSubscribedEvents(): array {
return [
'onContentAfterSave' => 'syncToCrm',
];
}
public function syncToCrm(Event $event): void {
[$context, $article, $isNew] = array_values($event->getArguments());
// Синхронизировать только статьи
if ($context !== 'com_content.article') return;
// Только опубликованные
if ((int) $article->state !== 1) return;
$syncTypes = $this->params->get('sync_types', []);
if (!in_array('article', (array) $syncTypes)) return;
try {
$this->sendToCrm([
'type' => 'article',
'external_id'=> $article->id,
'title' => $article->title,
'url' => \Joomla\CMS\Router\Route::link('site', 'index.php?option=com_content&view=article&id=' . $article->id),
'published' => (bool) $article->state,
'updated_at' => $article->modified,
]);
} catch (\Exception $e) {
$this->getApplication()->getLogger()->error('CRM sync failed: ' . $e->getMessage());
}
}
private function sendToCrm(array $data): void {
$apiUrl = rtrim($this->params->get('crm_api_url'), '/') . '/articles';
$apiKey = $this->params->get('crm_api_key');
$http = \Joomla\CMS\Factory::getContainer()
->get(\Joomla\Http\HttpFactory::class)
->getHttp();
$response = $http->post($apiUrl, json_encode($data), [
'Content-Type' => 'application/json',
'Authorization' => 'Bearer ' . $apiKey,
]);
if ($response->code >= 400) {
throw new \RuntimeException('CRM API error: ' . $response->code);
}
}
}
Плагин аутентификации (внешний SSO)
public static function getSubscribedEvents(): array {
return ['onUserAuthenticate' => 'authenticate'];
}
public function authenticate(Event $event): void {
$credentials = $event->getArgument('credentials');
$options = $event->getArgument('options');
$response = $event->getArgument('response');
// Проверяем через внешний OAuth-сервер
$token = $this->verifyWithOAuthServer($credentials['username'], $credentials['password']);
if ($token) {
$response->status = \Joomla\CMS\Authentication\Authentication::STATUS_SUCCESS;
$response->email = $token['email'];
$response->fullname = $token['name'];
$response->type = 'OAuth';
} else {
$response->status = \Joomla\CMS\Authentication\Authentication::STATUS_FAILURE;
$response->error_message = 'Неверные учётные данные';
}
}
Сроки
Разработка плагина для одной группы событий (content, user или system) с конфигурируемыми параметрами — 1–3 дня.







