Создание плагинов с учётом новой структуры Joomla 4

С момента выхода Joomla 4 прошло уже почти 2 года, поэтому слово "новой" будем понимать в контексте сравнения с Joomla 3. В Joomla 4 "под капотом" произошло немало изменений. Кодовая база движка постепенно отбрасывает legacy (старый код), встретившись с которым мы могли бы как на машине времени вернуться в середину 2000-х или начало 2010-х 😀. Статья первоначально опубликована на Хабре. Копирую к себе.

 
Собеседник в последний раз видел Joomla лет 12-15 назад.

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

В данной статье пойдёт речь о том, как создать плагин (или обновить старый) для Joomla 4 с новой структурой файлов и классов.

Отступление

Я предполагаю, что часть читателей имеет опыт работы с Joomla, но не имеет опыта создания плагинов, поэтому постараюсь описать создание плагина как можно подробнее. Статья имеет сугубо прикладной характер, без погружения в теорию ООП и его реализацию в Joomla. Основная цель - подсказать что "делать руками", когда поставлена определённая задача.

Также я предполагаю, что часть разработчиков могут встретиться с Joomla впервые. В терминологии Joomla "плагин" - это расширение, которое предоставляет функции, которые связаны с событиями (Event Dispatching). Когда происходит вызов конкретного события, то происходит последовательное выполнение всех функций подключаемых плагинов, связанных с этим событием. События могут вызывать как ядро Joomla, так и компоненты, да и в принципе любые расширения Joomla. Для сравнения, в терминологии WordPress "плагин" - это то, что в Joomla называется "компонент".

Плагины могут выполнять самый разный функционал в зависимости от времени и места вызываемого события, по которому они срабатывают: можно добавить кнопку like к материалу, а можно отправить данные заказа по API в CRM систему, "прочесать" весь готовый HTML-код страницы регуляркой или добавить новые команды в Joomla CLI интерфейс.

Поскольку в Joomla начиная с версий 3.2 начинают вводится namespaces , а в Joomla 4 добавляется паттерн Service locator (подробнее о DI и Service locator в Joomla) - в примерах кода неизбежно будут встречаться специфичные для конкретного расширения имена классов, названия файлов. При создании своего плагина, естественно, нужно изменить их на свои.

Файловая структура плагина Joomla 3

файловая структура плагина SEF Joomla 3
Старая файловая структура плагина Joomla 3

Для создания плагина в Joomla 3 было необходимо минимум 2 файла:

  • xml-манифест плагина - описание плагина для установщика расширений Joomla (системное имя, дата, версия, сайт разработчика и т.д.), параметры конфигурации плагина, сервер обновлений и т.д.

  • файл класса плагина - "точка входа" в плагин. С этого файла начиналась работа Вашего кода.

3
Файловая структура плагина инсталлера Joomla

Плагины, которые работают с HTML-кодом, могут иметь собственные макеты вывода. Такие макеты могут располагаться в папках tmpl и/или layouts, в зависимости от назначения этого макета (макет таба в табсете, макет для рендера изображения, макет ссылки, кнопки и любой другой запчасти - чаще всего layout). Также на это влияет выбранный разработчиком метод работы с HTML в коде - использует ли он классы для работы макетами Joomla\CMS\Layout\FileLayout (ex. JFileLayout) или Joomla\CMS\Layout\LayoutHelper (ex.JLayoutHelper). Порой плагин и просто echo $any_text; делает. Тогда у него может не быть макета вывода.

Файловая структура плагина для интеграции Joomla 3 с Битрикс 24
Файловая структура плагина для интеграции Joomla 3 с Битрикс 24

Некоторые плагины по функционалу приближаются к компонентам. В них сложнее файловая структура, они могут нуждаться в сторонних библиотеках для своей работы. Немало разработчиков, в попытке создать standalone-решение помещали всё необходимое в директорию с плагином. Для таких случаев в Joomla есть отдельный тип расширения - пакет (package), но это тема для отдельной статьи.

Файловая структура плагина в Joomla 4

Общие положения, как для модулей так и для плагинов Joomla 4: все необходимые для работы логики плагина файла мы помещаем в папку src - файл плагина, дополнительные библиотеки, файлы классов полей и т.д.. Макеты по прежнему находятся в корне плагина в tmpl и layouts.

Файловая структура плагина в Joomla 4
Файловая структура плагина в Joomla 4

Файл XML-манифеста плагина

Этот файл содержит описание плагина для установщика расширений Joomla (системное имя, группу плагина, дата создания, версия, сайт разработчика и т.д.), параметры конфигурации, сервер обновлений, а также задаёт Namespace плагина и директории для автозагрузки классов. Регистрация Namespace плагина в реестре происходит при установке расширения. На данный момент (Joomla 4.3.1) список классов для автозагрузки находится в файле administrator/cache/autoload_psr4.php. Он обновляется после каждой установки или обновления расширения.

Namespace плагина Joomla 4 в xml-манифесте на примере плагина для Radical Form  и AmoCRM
Namespace плагина Joomla 4 в xml-манифесте на примере плагина для Radical Form и AmoCRM

На заметку: Список соответствий названий старых классов Joomla и новых (алиасы) находится в libraries/classmap.php.

Обратите внимание, что namespace плагина должен содержать в себе группу плагина: Joomla\Plugin\System\YourclassJoomla\Plugin\Content\Yourclass и так далее.

Пример xml-манифеста плагина Joomla 4
Пример xml-манифеста плагина Joomla 4

Также стоит иметь в виду, что перевод расширений ядра Joomla на новую структуру на момент написания статьи ещё идёт и ожидается, что будет полностью завершён в Joomla 4.4. Например, для плагинов кнопки редактора (группа editors-xtd) переход на новую структуру до версии Joomla 4.4 не имеет смысла, так как ядро 4.0-4.3 ещё не поддерживает этот namespace.

Шаблон xml-манифеста для плагина Joomla 4.

<?xml version="1.0"?>
<extension type="plugin" method="upgrade" group="system">
    <name>PLG_WT_AMOCRM_RADICALFORM</name>
    <author>Sergey Tolkachyov</author>
    <authorEmail>info@web-tolk.ru</authorEmail>
    <authorUrl>https://web-tolk.ru/</authorUrl>
	<creationDate>06/12/2022</creationDate>
    <copyright>Sergey Tolkachyov</copyright>
    <license>GNU General Public License v3.0</license>
    <version>1.0.1</version>
    <description>PLG_WT_AMOCRM_RADICALFORM_DESC</description>
    <namespace path="src">Joomla\Plugin\System\Wt_amocrm_radicalform</namespace>
    <media folder="media" destination="plg_system_wt_amocrm_radicalform">
        <folder>js</folder>
    </media>
	<files>
        <folder plugin="wt_amocrm_radicalform">src</folder>
		<folder>services</folder>
        <filename>wt_amocrm_radicalform.xml</filename>
    </files>
    <languages folder="language" client="administrator">
        <language tag="en-GB">en-GB/plg_system_wt_amocrm_radicalform.ini</language>
        <language tag="ru-RU">ru-RU/plg_system_wt_amocrm_radicalform.ini</language>
        <language tag="en-GB">en-GB/plg_system_wt_amocrm_radicalform.sys.ini</language>
        <language tag="ru-RU">ru-RU/plg_system_wt_amocrm_radicalform.sys.ini</language>
    </languages>
    <config>
        <fields name="params">
            <fieldset name="basic">
              <!-- ЗДЕСЬ ПАРАМЕТРЫ ВАШЕГО ПЛАГИНА -->
              <!-- ТИПЫ ПОЛЕЙ JOOMLA ЗДЕСЬ -->
              <!-- https://docs.joomla.org/Standard_form_field_types -->
            </fieldset>
        </fields>
    </config>
</extension>

Также обратите внимание, что для корректной установки и работы плагина нужно указывать атрибут plugin="wt_amocrm_radicalform" в xml-манифесте. Если в Joomla 3 этот атрибут указывался для файла "точки входа" (<filename plugin="wt_amocrm_radicalform">wt_amocrm_radicalform.php</filename>), то сейчас он указывается для папки src плагина - <folder plugin="wt_amocrm_radicalform">src</folder> .

Языковые файлы (файлы локализации)

Ещё одно нововведение связано с языковыми файлами: теперь в именах файлов не обязательно дублировать префикс языка - "ru-RU.plg_system_wt_amocrm_radicalform.ini". Достаточно того, что файл лежит в папке "ru-RU". Однако, по-прежнему в названии файла локализации должен быть указан тип расширения plg, группа плагина (в данном случае system) и системное имя - из атрибута plugin="wt_amocrm_radicalform" - в сумме получается plg_system_wt_amocrm_radicalform.

Также помним, что файлы с языковыми константами (файлы локализации) должны отправляться в папку administrator/language, так как один и тот же плагин может работать и "внутри" и "снаружи". Для этого указываем атрибут client="administrator":

<languages folder="language" client="administrator">

Файл services/provider.php

Минимально необходимый набор для плагина увеличился на 1 файл. Аналогично, как и для модулей (статья Создание модулей с учётом новой структуры Joomla 4), плагину нужен файл сервис-провайдер Вашего плагина. Файл provider.php позволяет регистрировать плагин в DI-контейнере Joomla и даёт возможность обращаться к методам плагина извне с помощью MVCFactory.

<?php
/**
 *  @package   WT AmoCRM Radical Form
 *  @copyright Copyright Sergey Tolkachyov
 *  @license   GNU General Public License version 3, or later
 */

defined('_JEXEC') || die;

use Joomla\CMS\Extension\PluginInterface;
use Joomla\CMS\Plugin\PluginHelper;
use Joomla\DI\Container;
use Joomla\DI\ServiceProviderInterface;
use Joomla\Event\DispatcherInterface;
use Joomla\Plugin\System\Wt_amocrm_radicalform\Extension\Wt_amocrm_radicalform;

return new class () implements ServiceProviderInterface {
	/**
	 * Registers the service provider with a DI container.
	 *
	 * @param   Container  $container  The DI container.
	 *
	 * @return  void
	 *
	 * @since   4.0.0
	 */
	public function register(Container $container)
	{
		$container->set(
			PluginInterface::class,
			function (Container $container) {
				$subject = $container->get(DispatcherInterface::class);
				$config  = (array) PluginHelper::getPlugin('system', 'wt_amocrm_radicalform');
				return new Wt_amocrm_radicalform($subject, $config);
			}
		);
	}
};

Поскольку плагины по-прежнему расширяют класс CMSPlugin (ex. JPlugin), Вы можете установить объект приложения (Factory::getApplication()) плагину прямо в сервис-провайдере. И затем в самом плагине Вы сможете обращаться к объекту приложения с помощью $app = $this->getApplication(); Аналогично для удобства можно один раз указать объект для работы с базой данных: $plugin->set Database($container->get(DatabaseInterface::class));. И получить его в плагине $db = $this->getDatabase();.

<?php
/**
* Пример взят из книги греческого разработчика 
* Николаса Дионисопулоса, Akeeba Ltd.
* @link https://www.dionysopoulos.me/book/plg.html
*/
defined('_JEXEC') || die;

use Joomla\CMS\Extension\PluginInterface;
use Joomla\CMS\Factory;
use Joomla\CMS\Plugin\PluginHelper;
use Joomla\DI\Container;
use Joomla\DI\ServiceProviderInterface;
use Joomla\Event\DispatcherInterface;
use Joomla\Database\DatabaseInterface;
use Acme\Plugin\System\Example\Extension\Example;

return new class implements ServiceProviderInterface {
    public function register(Container $container)
    {
        $container->set(
            PluginInterface::class,
            function (Container $container)
            {
                $config  = (array)PluginHelper::getPlugin('system', 'example');
                $subject = $container->get(DispatcherInterface::class);

                $app = Factory::getApplication();

                /** @var \Joomla\CMS\Plugin\CMSPlugin $plugin */
                $plugin = new Example($subject, $config);
                $plugin->setApplication($app);
                $plugin->setDatabase($container->get(DatabaseInterface::class));

                return $plugin;
            }
        );
    }
};

Также обратите внимание на изменения в Joomla 4.4, в них классы модулей и плагинов становятся final, добавляется использование trait. В целом на работу Вашего кода это не должно влиять.

Скриншот кода Joomla со страницы гитхаба

Файл класса плагина

Это файл, в котором содержится основной рабочий код Вашего плагина. Он должен находится в папке src/Extension. Регистр названия имеет значение: Extension и extension - 2 разных папки.

Если Вы адаптируете старый плагин Joomla для работы в Joomla 4, то нужно сделать:

  • перенести php-файл плагина в папку src/Extension

  • изменить имя файла так, чтобы оно начиналось с заглавной буквы - Wt_amocrm_radicalform,

  • изменить имя класса с PlgSystemWt_amocrm_radicalform на Wt_amocrm_radicalform. Вся строка будет вида class Wt_amocrm_radicalform extends CMSPlugin

  • в самом начале файла указать его namespace - namespace Joomla\Plugin\System\Wt_amocrm_radicalform\Extension;

  • проверить, чтобы все названия событий (функций в плагине) начинались с "on" - onBeforeCompileHeadonAfterRender и т.д.

Пример кода класса плагина Joomla 4

Если Ваш плагин был написан "по технологиям" Joomla 3.x, с использованием namespaces, то в большинстве случаев он будет работать на Joomla 4. Если же плагин использовал код, работавший ещё в 1.5-1.6 и бывший устаревшим уже в Joomla 3, то, скорее всего, плагин нужно будет пересобрать.

<?php
/**
 * @package     WT Amocrm - Radical From
 * @version     1.0.0
 * @Author      Sergey Tolkachyov, https://web-tolk.ru
 * @copyright   Copyright (C) 2022 Sergey Tolkachyov
 * @license     GNU/GPL3
 * @since       1.0
 */

// No direct access

namespace Joomla\Plugin\System\Wt_amocrm_radicalform\Extension;

defined('_JEXEC') or die;

use Joomla\CMS\Plugin\CMSPlugin;
use Joomla\CMS\Factory;
use Joomla\CMS\Date\Date;
use Webtolk\Amocrm\Amocrm;

class Wt_amocrm_radicalform extends CMSPlugin
{

	/**
	 * Добавляем js-скрпиты на HTML-фронт
	 *
	 * @throws \Exception
	 * @since 1.0.0
	 */
	function onAfterDispatch()
	{
		// We are not work in Joomla API or CLI ar Admin area
		if (!Factory::getApplication()->isClient('site')) return;

		$doc = Factory::getApplication()->getDocument();
		// We are work only in HTML, not JSON, RSS etc.
		if (!($doc instanceof \Joomla\CMS\Document\HtmlDocument))
		{
			return;
		}

		$wa = $doc->getWebAssetManager();
		// Show plugin version in browser console from js-script for UTM
		$wt_amocrm_radicalform_plugin_info = simplexml_load_file(JPATH_SITE . "/plugins/system/wt_amocrm_radicalform/wt_amocrm_radicalform.xml");
		$doc->addScriptOptions('plg_system_wt_amocrm_radicalform_version', (string) $wt_amocrm_radicalform_plugin_info->version);
		$wa->registerAndUseScript('plg_system_wt_amocrm_radicalform.wt_amocrm_radicalform_utm', 'plg_system_wt_amocrm_radicalform/wt_amocrm_radicalform_utm.js', array('version' => 'auto', 'relative' => true));

	}
  }

Новая система событий для плагинов в Joomla 4

Кратко: в Joomla 4 реализована новая система событий, основанная на SubscriberInterface .Класс плагина реализует \Joomla\Event\SubscriberInterface, Вы устанавливаете свойство protected $this->allowLegacyListeners = false;. Это изменяет способ, которым Joomla регистрирует обработчики событий. В этом режиме Joomla не будет использовать рефлексию и искать публичные методы, чьи имена начинаются с on. Вместо этого она вызовет публичный статический метод getSubscribedEvents, который определен в интерфейсе и должен быть реализован в классе вашего плагина. Этот класс вернёт массив с маппингом событий и методов Вашего плагина. При этом внутри Вашего плагина методы уже не обязаны начинаться с on и вообще могут иметь любое (в разумных пределах) название. Отсутствие необходимости проходить через рефлексию экономит много времени при загрузке каждой страницы сайта. Кроме того, события представляют собой автономные объекты, которые передаются, что снижает накладные расходы на вызов каждого обработчика событий. К ним добавляются десятки и сотни плагинов и обработчиков событий, работающих на типичном сайте Joomla, что экономит от нескольких десятков до нескольких сотен миллисекунд времени загрузки страницы. Это значительное улучшение производительности сайта.

Подробно: это потребует отдельной статьи 😀

Пример кода плагина, использующего SubscriberInterface в Joomla 4.

<?php
namespace Joomla\Plugin\Quickicon\Joomlaupdate\Extension;

use Joomla\CMS\Plugin\CMSPlugin;
use Joomla\Event\SubscriberInterface;
use Joomla\Module\Quickicon\Administrator\Event\QuickIconsEvent;

class Joomlaupdate extends CMSPlugin implements SubscriberInterface
{
    
    /**
     * Returns an array of events this subscriber will listen to.
     *
     * @return  array
     *
     * @since   4.0.0
     */
    public static function getSubscribedEvents(): array
    {
        return [
            'onGetIcons' => 'getCoreUpdateNotification',
        ];
    }

    /**
     * This method is called when the Quick Icons module is constructing its set
     * of icons. You can return an array which defines a single icon and it will
     * be rendered right after the stock Quick Icons.
     *
     * @param   QuickIconsEvent  $event  The event object
     *
     * @return  void
     *
     * @since   4.0.0
     */
    public function getCoreUpdateNotification(QuickIconsEvent $event)
    {
    
    }
}

Это несколько сокращённый код плагина, который добавляет иконку с уведомлениями о новых версиях Joomla, код можно посмотреть здесь: plugins/quickicon/joomlaupdate/src/Extension/Joomlaupdate.php.

Что здесь происходит? Плагин реализует SubscriberInterface и имеет статический публичный метод getSubscribedEvents, который возвращает массив сопоставления событий и методов плагина. Обратите внимание, что по событию onGetIcons будет вызван не метод плагина onGetIcons (его там и нет вообще), а метод getCoreUpdateNotification.

Ещё один пример кода (источник):

<?php
public static function getSubscribedEvents(): array
{
    return [
        'onSomething'     => 'doSomething',
        'onSomethingElse' => ['doSomething', \Joomla\Event\Priority::HIGH],
    ];
}

onSomething - некое событие, вызывающее метод нашего плагина doSomethingonSomethingElse - другое событие. которое вызывает метод нашего плагина doSomething и устанавливает исполнению этого метода приоритет.

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

Небольшое "но"...

Ядро Joomla 4 (4.3.1 на момент написания статьи) до сих пор ещё содержит старые вызовы плагинов. Поэтому, перед тем, как переписать плагин на новую структуру - убедитесь, что событие плагина вызывается по-новому. Это будет выглядеть в коде примерно так:

<?php
$event = \Joomla\CMS\Event\AbstractEvent::create('onSomething', [$param1 => $value1, $param2 => $value2]);
$this->getDispatcher()->dispatch($event->getName(), $event);
$results = $event->getArgument('result', []);

Для сравнения, старый способ вызова событий выглядел примерно таким образом: $app->triggerEvent('onSomething', [$param1, $param2]).

Самый простой способ выяснить как образом вызывается событие для плагина - выполнить поиск по текстовому содержимому движка (если Вы работаете без IDE), а затем найти вызов в файле

Поиск по текстовому содержимому файлов php
Поиск по названию события в коде Joomla 4.
Поиск вызова метода плагина в коде файла.
Поиск вызова метода плагина в коде файла.

Для примера, я решил перевести один из своих плагинов для JoomShopping на новую структуру Joomla 4. Немного почитав код ядра и документацию стал пробовать новый метод, но на JoomShopping он не завёлся, так как JoomShopping - это не ядро Joomla, а сторонний компонент и вызовы событий в нём реализуются пока что старыми методами. В этом плане, Вы как разработчик зависите от компонента, под который Вы разрабатываете плагин. Будьте внимательны и осторожны 😀.

UPD. 16.09.2023: Возможно использовать в плагине новую систему вызовов и получать в качестве аргумента объект Event $event, но если при этом если событие плагина вызывается по-старому, то обращение к параметрам будет идти по числовому индексу:

<?php
$param1 = $event->getArgument(0);
$param2 = $event->getArgument(1);

Upd. 29.03.2024. Возврат значений:

Вариант 1.

Мы должны получить массив с результатами работы плагинов, добавить туда свой результат и положить всё обратно.

<?php
// Пример из плагина QuickIcon админки

// Add the icon to the result array
  $result = $event->getArgument('result', []);

  $result[] = [
      [
          'link'  => $privacy . '&view=requests&filter[status]=1&list[fullordering]=a.requested_at ASC',
          'image' => 'icon-users',
          'icon'  => '',
          'text'  => $this->getApplication()->getLanguage()->_('PLG_QUICKICON_PRIVACYCHECK_CHECKING'),
          'id'    => 'plg_quickicon_privacycheck',
          'group' => 'MOD_QUICKICON_USERS',
      ],
  ];

  $event->setArgument('result', $result);

Нужно помнить, что этот способ помечен в коде Joomla 4.x как устаревший (deprecated) и будет удалён в Joomla 6. Речь идёт именно о setArgument('result', $result).

Вариант 2. Назначение аргументов по индексу.

Как мы их получали, так и возвращаем.

<?php

$param1 = $event->getArgument(0);
$param2 = $event->getArgument(1);

// Что-то с ними делаем....

$event->setArgument(0, $param1);
$event->setArgument(1, $param1);

Вариант 3. Использование метода $event->addResult().

Этот метод был добавлен в Joomla 4.2. Он берёт на себя работу, описанную выше.

<?php

// результат работы плагина
$result = $this->onCustomFieldsGetTypes();

if ($result) {
    $event->addResult($result);
}

Сами методы плагина (кроме getSubscribedEvents()) должны возвращать пустоту - void

Работа с Ajax в плагинах Joomla 4

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

Пример метода для получения данных из плагина по ajax в Joomla 4
Пример метода для получения данных из плагина по ajax в Joomla 4

Пример ajax-запроса, реализованного нативными средствами Joomla (статья-мануал).

Joomla.request({   
				url: window.location.origin + "/index.php?option=com_ajax&plugin=yourplugin&group=system&format=raw",
				onSuccess: function (response, xhr){
                     if (response !== ""){
    					// Здесь делаем то, что нужно			
                     }
				}
			});

		}

Свои типы полей Joomla для плагина

Поля Joomla Form указываются в XML-манифесте и представляют собой удобный и быстрый конструктор интерфейса. Как и в Joomla 3, в Joomla 4, если Вам не хватает стандартных типов полей, у Вас есть возможность создавать свои типы полей. Это могут быть нестандартные выборки из базы данных, получение значений списка из сторонних сервисов по API и т.д.

Возможность создавать свои пользовательские типы полей открывает широкие возможности Joomla. Наглядный пример про Битрикс 24 приводил в статье про написание модулей по структуре Joomla 4 (хотя пример как раз из плагина... )).

Joomla 3

В Joomla 3 Вам надо было указать свой тип поля и назначить атрибут addfieldpath родительскому <fieldset> или напрямую <field>. Например

<field addfieldpath="plugins/system/wt_amocrm_radicalform/fields" type="plugininfo" name="plugininfo"/>

Php-файл поля находился в папке с плагином plugins/system/wt_amocrm_radicalform/fields.

Joomla 4

В Joomla 4 атрибут addfieldpath не работает. Вместо него используется атрибут addfieldprefix, в котором нужно указать namespace для пользовательских полей плагина.

Собственные типы полей в Joomla 4
Собственные типы полей в Joomla 4

Поля мы складываем в src/Fields. У файлов полей должен быть namespace namespace Joomla\Plugin\System\Wt_amocrm_radicalform\Fields. Я использую собственный тип поля, расширяющий тип поля spacer (пробел), для вывода своего логотипа, версии плагина, ссылки на сайт и иногда дополнительной информации.

К слову сказать, классы дополнительных типов полей могут находиться и не в папке с плагином, а, например, быть "в комплекте" с библиотекой и физически находиться в папке libraries. Но, указав нужный namespace в атрибуте addfieldprefix мы можем легко их использовать.

В этом примере первое поле field загружается из папки с плагином, а второе поле - из библиотеки WT AmoCRM.
В этом примере первое поле <field> загружается из папки с плагином, а второе поле - из библиотеки WT AmoCRM.

Полезные дополнения

Об использовании \Joomla\CMS\Factory

Из статьи Распространенные ошибки при написании плагинов Joomla 4

Вы должны использовать ТОЛЬКО ДВА метода \Joomla\CMS\Factory в Joomla 4:

  • getContainer() - возвращает контейнер внедрения зависимостей Joomla (DI Container, иногда сокращенно DIC).

  • getApplication() - возвращает текущий объект приложения Joomla, обрабатывающий запрос.

Всё. Больше ничего другого использовать не нужно! Всё остальное предоставляется либо через DI-контейнер, либо через сам объект приложения.

Чтобы получить документ приложения используйте \Joomla\CMS\Factory::getApplication()->getDocument().

Правильное подключение CSS и JS в Joomla 4

  1. Статья Как правильно подключать JavaScript и CSS в Joomla 4

  2. Статья на хабре Использование WebAssetsManager Joomla 4 и добавление собственных пресетов с помощью плагина. Мы помним, что все CSS и JS файлы должны лежать в папке media. Подробнее в статьях.

  3. Статья на хабре Создание модулей с учётом новой структуры Joomla 4

Замена для популярных, но устаревших методов

Многие из этих методов работали ещё со времен Joomla 1.5 (с 2008 года!).

  • JRequest::getUri() заменяем на $uri = Joomla\CMS\Uri::getInstance() и читаем документацию к нему.

  • методы JRequest::getCmd и аналогичные перекочевали в Joomla\Input\Input или (что проще) $app->getInput(). Пока что поддерживается устаревший синтаксис $app->input, но в Joomla 5 (выйдет осенью 2023 года) он может быть удалён (план выпуска релизов и принципы удаления устаревшего кода в Joomla).

  • $app->isAdmin() и $app->isSite() стали $app->isClient('Site') и $app->isClient('Administrator').

  • Подключение к базе данных: вместо JFactory::getDbo() (или Joomla\CMS\Factory::getDbo) используем $app->getContainer()->get('DatabaseDriver') ('DatabaseDriver' регистрозависимый). Или же use Joomla\Database\DatabaseInterface; в начале файла в секции с use. И Factory::getContainer()->get(DatabaseInterface::class).

  • Получение объекта пользователя: вместо JFactory::getUser() (или Joomla\CMS\Factory::getUser()используем $app->getIdentity()

  • Получение языка: вместо Factory::getLanguage() используем Factory::getApplication()->getLanguage();

  • Список соответствий названий старых классов Joomla и новых (алиасы) находится в libraries/classmap.php.

Толкачев Сергей Юрьевич
Толкачев Сергей Юрьевич

Joomla-разработчик. Контрибьютер ядра Joomla. Один из ведущих Telegram-канала русскоязычного Joomla-сообщества JoomlaFeed, один из модераторов чата русскоязычного Joomla-сообщества. Мои расширения в официальном маркетплейсе расширений Joomla - Joomla Extensions Directory. Имею публикации в официальном журнале международного Joomla-сообщества - Joomla Community Magazine.

Муж. Отец 3 детей.

Россия, Саратов.

Расширения Joomla WebTolk

90 Всего расширений
11 Категорий
399 Выпущено версий
387363 Всего скачиваний
Корзина
Корзина пуста