На вашем сайте, внутреннем портале, в интернет-магазине кто-то что-то сделал, а потом всё сломалось: сайт открывается криво (или не открывается вообще?), перестали работать фоновые задачи в планировщике, установились неправильные скидки всем пользователям на все товары… Предположим, что с безопасностью у вас всё хорошо: Joomla свежая, актуальная, расширения — тоже. Да и в логах сервера и логах Joomla тоже чисто… Тогда остаётся ещё один источник информации — Лог действий пользователей Joomla. Основная его задача — помочь быстро найти кому настучать по рогам причину и устранить её.
Всё, что связано с действиями в админке — может логироваться: от обновления системы и компонентов, изменения настроек до редактирования и сохранения конкретных элементов (статьи, товары, категории и т.д.) и загрузки файлов через медиа менеджер. Лично мне нередко этот функционал помогал найти тех контент-менеджеров, кто дублирует названия товаров, создавая дубли и тем самым негативно влияя на SEO. Или же вдруг обнаруживается недозаполненная, но опубликованная карточка товара, которой не должно было быть, но она появилась. И ладно если б это был единичный случай.
Оговорка 1: статья рассчитана не только на тех, кто хорошо знает Joomla, но и на любопытствующих коллег из других технологических стеков. Поэтому некоторым очевидным терминам всё равно дано краткое пояснение.
Оговорка 2: на данный момент я рассматриваю Joomla скорее как PHP-фреймворк с натянутой на него готовой админкой, а не просто CMS. Расширение типа «компонент» в Joomla обычно представляет из себя набор различных CRUD-ов (в терминологии PHP-фреймворков), записи о действиях в которых можно хранить в логах. Поэтому статью следует больше рассматривать как начальную точку для проектирования и написания своего плагина (расширение, срабатывающие на триггеры событий Event Dispatcher) для своего же (скорее всего) компонента (CRUD-а).
Оглавление
-
Список литературы
Список литературы
-
User Action Logs — документация для Joomla 3. Практически все положения из неё остались верны и для последующих версий.
-
Joomla User Manual — чуть обновлённый вариант документации для Joomla 5. Так же есть ИИ-перевод на русский язык.
-
На новом портале документации Joomla manual.joomla.org на момент написания статьи ещё нет примера плагина Action log, но ссылку оставлю, так как вся актуальная информация по ядру собирается именно там.
-
Триггеры ядра Joomla при CRUD-операциях — сопутствующая статья.
-
Создание плагинов с учётом новой структуры Joomla 4 — сопутствующая статья.
-
Joomla Extensions Development — объёмная книга греческого разработчика Никалоса Дионисопулоса. Посвящена Joomla разработке в целом, освещает вопросы архитектуры, причины применения некоторых подходов и т.д.
Описание возможностей компонента Лога пользователей Joomla
Этот компонент был добавлен в ядро Joomla начиная с версии 3.9.0. Найти его можно в левом меню панели администратора: Пользователи — Лог действий пользователей.

Он предоставляет собой простой интерфейс для чтения и фильтрации записей.
На скриншоте я выделил колонку «расширение». По ней можно понять контекст записи о действии. На скриншоте видны разные компоненты:
-
«расширения» — действия, связанные с установкой, удалением и обновлением расширений, сохранением параметров.
-
«материалы» — штатный компонент для создания статей в Joomla. Его же нередко используют для создания каталогов чего угодно.
-
«SW JProjects» — сторонний компонент Joomla для ведения каталога расширений Joomla и сервера обновлений для них
-
«Лог действий» — собственно компонент лога действий пользователя Joomla
Так, например, компонент «пользователи» (com_users) логирует не только собственно действия с пользователями, но и моменты входа и выхода в админку.

Правильный выход через кнопку «выйти» в наше время никто не делает, конечно. Это скорее исключение, так как все просто закрывают вкладку браузера. Но момент входа записывается точно, поэтому даже если какой-то компонент не умеет записывать логи об интересующих нас действиях пользователей, мы можем резко сузить круг «подозреваемых лиц» до тех, кто в данный момент времени находился в админке.
Мы можем отфильтровать записи по типу расширения и увидеть только то, что нас интересует. Для этого пользуемся кнопкой «параметры поиска» в списке записей событий. Список расширений зависит от установленных компонентов и того, поддерживают ли они стандартный для Joomla action log.
Также есть возможность отфильтровать действия по конкретному пользователю и за выбранный период времени. К сожалению, периоды времени пока что не настраиваются и доступны только предустановленные значения.

Ну и конечно доступна фильтрация записей по конкретному пользователю.
Параметры компонента Лог действий пользователя в Joomla
Настраиваемых параметров немного. Мы можем дополнительно логировать IP-адрес пользователя. По умолчанию эта функция отключена, видимо из-за европейских GDPR.
Самое полезное здесь — это настройка списка компонентов, в которых должны логироваться события.
Самое интересное здесь — возможность логирования запросов к REST API Joomla.

Если мы включим параметр «логировать запросы», то в выпадающем списке можно выбрать какие именно методы логировать: GET (получение данных по REST API). POST (создание сущности) и т.д. Подробнее о REST API в статье на Хабре «Web Services в Joomla 4».
Таким образом если ваша Joomla связана с внешними системами по REST API, то историю взаимодействия с ними тоже можно отслеживать.
Версионность контента. Просмотр изменений.
Порой нам хотелось бы знать что именно было изменено и на что. Версионность контента возможна только в тех компонентах, что его поддерживают и где параметр сохранения версий включён. Так, в стандартных материалах Joomla должен быть включён параметр в настройках компонента — Форма — История версий.

Тогда на странице редактирования материала Joomla появится кнопка «версии».

Где можно не только их просмотреть и восстановить…

… но и сравнить, увидев конкретные внесённые изменения. Изменения показываются в отдельном всплывающем окне. Изменения подсвечиваются.

Если вы пишете свой собственный компонент, то можете реализовать это удобнее с точки зрения пользовательского опыта и в своём сообщении добавить сразу ссылку на diff-ы.
Архитектура базы данных
В базе данных Joomla 4 таблицы, связанных с логированием действий пользователей:
-
#__actionlogs— основная таблица для хранения логов -
#__actionlogs_extensions— таблица для хранения списка логируемых расширений. Данные этой таблицы образуют список компонентов для параметра Логировать действия в расширениях в настройках компонента. Столбецextensionв ней содержит значение системного имени компонента видаcom_content,com_menus,com_modulesи т.д. -
#__actionlogs_users— параметры логирования действий для конкретных пользователей. Эти параметры можно настроить в профиле пользователя, вкладка «Лог действий» -
#__action_log_config— параметры для конструирования языковой константы сообщения лога и данных для неё.
Анализ плагина action logs ядра Joomla
В Joomla штатные действия ядра записывает плагин Лог действий — Joomla. Он не имеет настраиваемых параметров. Файл класса плагина находится в plugins/actionlog/joomla/src/Extension/Joomla.php.
Логика работы плагина в целом состоит из следующих шагов:
-
Проверить, в допустимом ли контексте вызвано событие. Обычно у компонента несколько сущностей (категории материалов и материалы; категории товаров, товары, производители товаров, характеристики товаров и т.д.), список их контекстов заносится в свойство класса плагина.
-
Получить системное имя компонента вида
com_mycomponent. В разных случаях мы получаем его или из контекста с помощьюexplode('.', $context), либо из$_GETмассива с помощью объектаInput:$option = $app->getInput()->get('option'). -
Проверить, а разрешено ли логировать действия в данном компоненте.
-
В зависимости от типа события — сконструировать языковую константу и получить данные для подмены плейсхолдеров в ней.
-
Собрать массив с сообщением и данными.
-
Добавить массив в лог.
Языковые константы
Языковые константы ядра Joomla для лога действий пользователя распределены между файлами локализаций двух плагинов — групп system и actionlog:
-
administrator/language/ru-RU/plg_actionlog_joomla.ini
-
administrator/language/ru-RU/plg_system_actionlogs.ini
Если мы откроем файлы локализации плагина группы actionlog Joomla, то увидим в нём следующие строки:
PLG_SYSTEM_ACTIONLOGS_CONTENT_ADDED="Пользователь <a href=\"{accountlink}\">{username}</a> создал {type} <a href=\"{itemlink}\">{title}</a>" PLG_SYSTEM_ACTIONLOGS_CONTENT_ARCHIVED="Пользователь <a href=\"{accountlink}\">{username}</a> переместил в архив {type} <a href=\"{itemlink}\">{title}</a>" PLG_SYSTEM_ACTIONLOGS_CONTENT_DELETED="Пользователь <a href=\"{accountlink}\">{username}</a> удалил {type} {title}" PLG_SYSTEM_ACTIONLOGS_CONTENT_PUBLISHED="Пользователь <a href=\"{accountlink}\">{username}</a> опубликовал {type} <a href=\"{itemlink}\">{title}</a>" PLG_SYSTEM_ACTIONLOGS_CONTENT_TRASHED="Пользователь <a href=\"{accountlink}\">{username}</a> переместил в корзину {type} <a href=\"{itemlink}\">{title}</a>" PLG_SYSTEM_ACTIONLOGS_CONTENT_UNPUBLISHED="Пользователь <a href=\"{accountlink}\">{username}</a> снял с публикации {type} <a href=\"{itemlink}\">{title}</a>" PLG_SYSTEM_ACTIONLOGS_CONTENT_UPDATED="Пользователь <a href=\"{accountlink}\">{username}</a> обновил {type} <a href=\"{itemlink}\">{title}</a>"
Имя языковой константы конструируется по формуле [text_prefix] + [entity] + [action].
$text_prefix — это обычно свойство контроллера или модели компонента. В нём хранится системное имя компонента: com_categories, com_content, com_menus. Или [имя компонента + сущность]: com_banners_client, com_banners_banners.

Набор типов действий по умолчанию в Joomla интуитивно понятны. Суффикс ADD для вновь созданных элементов, DELETED — для удалённых и т.д.
Фрагмент entity в имени языковой константы в Joomla по умолчанию равен «CONTENT». Он используется в случаях, когда отсутствуют созданные языковые константы, но вывести что-то нужно.
Типы изменяемых сущностей
Ещё ряд языковых констант даёт нам название типов изменяемых сущностей, отвечая на вопрос «что?» — что было изменено / создано / удалено и т.д. В файле administrator/language/ru-RU/plg_actionlog_joomla.ini это строки
;... PLG_ACTIONLOG_JOOMLA_TYPE_ARTICLE="материал" PLG_ACTIONLOG_JOOMLA_TYPE_BANNER="баннер" PLG_ACTIONLOG_JOOMLA_TYPE_BANNER_CLIENT="клиента" PLG_ACTIONLOG_JOOMLA_TYPE_CATEGORY="категорию" PLG_ACTIONLOG_JOOMLA_TYPE_COMPONENT="компонент" PLG_ACTIONLOG_JOOMLA_TYPE_COMPONENT_CONFIG="Настройки компонента" PLG_ACTIONLOG_JOOMLA_TYPE_CONTACT="контакт" PLG_ACTIONLOG_JOOMLA_TYPE_FIELD="поле" ;...
Они формируются по формуле [text_prefix] + _TYPE_ + [entity].
Плейсхолдеры в языковых константах (переменные для строковой замены)
Вы уже обратили внимание на переменные в составе языковых констант. В примере выше мы можем увидеть
-
{accountlink}— ссылку на пользователя в админке Joomla -
{username}— имя пользователя -
{type}— тип сущности: материал, баннер, модуль, параметры конфигурации, товар и т.д. -
{itemlink}— ссылка в админке на сущность, с которой произошло событие -
{title}— название / заголовок сущности
Также штатно обрабатываются ещё следующие плейсхолдеры, работающие везде:
-
{userid}— id юзера, совершающего действие. Используется для формирования ссылок на него. -
{app}— тип приложения: панель управления, API (Joomla REST API), CLI, сайт.
Некоторые плейсхолдеры используются только в определенных частях системы, например в REST API Joomla:
-
{verb}— для логирования запросов REST API — тип запроса GET, POST, PUT и т.д. -
{url}— для логирования запросов REST API — url запроса
Конструирование языковых констант
Посмотрим на структуру таблицы #__action_log_config. В ней содержатся необходимые данные для конструирования языковых констант и источники данных для плейсхолдеров.
-
text_prefix— см. о нём выше. Префикс для языковых констант. -
type_alias— содержит в себе контекст выполнения действия.$contextсодержит в себе системное имя компонента и сущности вида<com_component>.<entity>. Если в этом списке нет нужного контекста — штатный плагин Joomla не сработает. -
table_name— имя таблицы базы данных, из которых нужно выбирать данные в некоторых случаях. Например при смене состояния: опубликовано / не опубликовано * перемещено в корзину / перемещено в архив. При пакетных действиях на триггерonContentChangeStateприходит списокidи чтобы получить заголовок статьи нужно сходить за ним в базу. -
type_title— поле, в котором находится фрагмент языковой константы типа изменяемой сущности для данного контекста. Например, для контекстаcom_content.articleпри формировании языковой константы для плейсхолдера{type}будет создано PLG_ACTIONLOG_JOOMLA_TYPE_ARTICLE. -
id_holderиtitle_holder— содержат в себе названия свойств объектаTableизменяемой сущности. Например, если мы отслеживаем материал Joomla, то для ссылки на созданный / изменённый материал нам нужен егоidи он хранится в таблице#__contentв столбце с названиемid. Аналогично заголовок материала хранится в таблице#__contentв столбце с названиемtitle. Однако, у баннеров столбец для заголовка баннера называетсяnameи т.д.
Посмотрим на примере одного события onContentAfterSave как работает штатный плагин.
<?php // \Joomla\Plugin\Actionlog\Joomla\Extension\Joomla::onContentAfterSave // Файл plugins/actionlog/joomla/src/Extension/Joomla.php use Joomla\CMS\Event\Model; /** * After save content logging method * This method adds a record to #__action_logs contains (message, date, context, user) * Method is called right after the content is saved * * @param Model\AfterSaveEvent $event The event instance. * * @return void * * @since 3.9.0 */ public function onContentAfterSave(Model\AfterSaveEvent $event): void { // Контекст вида com_content.article $context = $event->getContext(); // Исторически это $article, хотя правильнее назвать $item $article = $event->getItem(); // Логический флаг: создаётся новый элемент или редактируется уже существующий $isNew = $event->getIsNew(); if (isset($this->contextAliases[$context])) { $context = $this->contextAliases[$context]; } // Параметры компонента. Тут находится список // разрешённых к логированию компонентов. // Этот список переопределяется настройками // конкретного юзера в его профиле. $params = $this->getActionLogParams($context); // Not found a valid content type, don't process further if ($params === null) { return; } // $option - это системное имя компонента вида com_component. [$option, $contentType] = explode('.', $params->type_alias); // Можно ли логировать действия в данном компонент для данного юзера? if (!$this->checkLoggable($option)) { return; } // Конструируем языковую константу // Добавляем нужные суффиксы к языковой константе. if ($isNew) { $messageLanguageKey = $params->text_prefix . '_' . $params->type_title . '_ADDED'; $defaultLanguageKey = 'PLG_SYSTEM_ACTIONLOGS_CONTENT_ADDED'; } else { $messageLanguageKey = $params->text_prefix . '_' . $params->type_title . '_UPDATED'; $defaultLanguageKey = 'PLG_SYSTEM_ACTIONLOGS_CONTENT_UPDATED'; } // If the content type doesn't have its own language key, use default language key if (!$this->getApplication()->getLanguage()->hasKey($messageLanguageKey)) { $messageLanguageKey = $defaultLanguageKey; } $id = empty($params->id_holder) ? 0 : $article->{$params->id_holder}; // Массив с сообщением $message = [ 'action' => $isNew ? 'add' : 'update', 'type' => $params->text_prefix . '_TYPE_' . $params->type_title, 'id' => $id, 'title' => $article->{$params->title_holder} ?? '', 'itemlink' => ActionlogsHelper::getContentTypeLink($option, $contentType, $id, $params->id_holder, $article), ]; $this->addLog([$message], $messageLanguageKey, $context); }
В массиве $message хранятся данные для плейсхолдеров в языковой константе. Дополнительно, 4-м аргументов в $this->addLog() можно передать id пользователя, для которого создаётся запись. Обычно это id текущего пользователя.
Решение без создания плагина
Можно обойтись и без создания собственного плагина. Если для вас сообщения вида «Пользователь [Сиреневый Енот] [обновил] [сущность] [ссылка на сущность]» достаточно информативны, то можно обойтись просто добавлением своих параметров в базу данных.
Вы добавляете свой компонент в список возможных логируемых компонентов (для выпадающего списка в настройках компонента Лог пользователей) в таблицу #__actionlogs_extensions и затем добавляете параметры для конструирования языковых констант в таблицу #__action_log_config. А дальше вам нужно лишь создать 4 файла локализации с текстами сообщений: 2 на английском и 2 на русском языках. Всю дальнейшую работу будет выполнять плагин ядра Joomla.
Сделать это можно при создании очередного релиза вашего компонента в sql-файлах пакета буквально парой запросов.
Задача решена. Дальше статью можно не читать.
Создание своего плагина
Если вам нужны более информативные сообщения в логах, где используется больше плейсхолдеров в языковых константах или же не все данные приходят в объекте Table изменяемой сущности, то тогда потребуется создать полноценный плагин. Создаём плагин группы actionlog по типовой для Joomla 4+ структуре файлов и классов. Здесь читаем статью Создание плагинов с учётом новой структуры Joomla 4.
Триггеры событий для плагинов (Event Dispatching)
Ранее писал статью «Триггеры ядра Joomla при CRUD-операциях», в которой рассказывается о различных событиях, вызываемых в моделях ядра Joomla. Модели компонентов ядра и немалая часть сторонних компонентов (но далеко не все) наследуют \Joomla\CMS\MVC\Model\AdminModel (libraries/src/MVC/Model/AdminModel.php). Поэтому в них доступны все стандартные события:
-
onContentBeforeDelete— перед удалением сущности -
onContentAfterDelete— после удаления -
onContentBeforeSave— перед сохранением данных сущности -
onContentAfterSave— после сохранения -
onContentBeforeChangeState— перед изменением состояния (опубликовано, не опубликовано, в корзине…) -
onContentChangeState— после изменения состояния -
onBeforeBatch— перед пакетной обработкой нескольких сущностей
В некоторых случаях названия события отличаются, подробнее об этом смотрим в указанной статье.
При триггере события в плагин передаются данные, для каждого события — свои. Приведу примеры:
onContentAfterSave — после сохранения
Событие вызывается после сохранения любой сущности в Joomla (повторюсь, если модели компонента наследуют AdminModel). В аргументах события мы имеем:
-
$context—string— контекст события вида<component_name>.<entity>:com_content.article,com_contact.contactи т.д. -
$article— объектTableсохранённой сущности. Вообще-то оно должно называться$item, так как это может быть не только статья, но и что угодно. Но видимо плагин изначально писали для материалов и оно так и осталось. -
$isNew—bool— логический флаг новая ли сущность или уже существующая. -
$data—array— данные отправленной в модель формы. Не все данные могут быть в объектеTable, некоторые поля формы могут храниться в других таблицах. Но в триггер передаётся лишь одна. Здесь зависит от того, какое поведение реализует модель компонента.
Штатный плагин подразумевает, что всё-таки большая часть данных формы хранится в одной основной таблице и аргумент $data не использует.
onContentAfterDelete — после удаления
Доступные аргументы — $context и $item. Необходимое нам системное имя компонента — получаем уже из объекта Input.
onContentChangeState — после смены состояния
Состояния: опубликовано / не опубликовано / в корзине / в архиве. Также ваш компонент может иметь собственную, более широкую систему состояний.
В аргументах события:
-
$context—string— контекст события вида<component_name>.<entity>:com_content.article,com_contact.contactи т.д. -
$pks—array— массив с id изменяемых сущностей. -
$value—int— числовое значение состояние.0— не опубликовано,1— опубликовано,2— в архиве,-2— в корзине.
Далее, на каждое событие вы конструируете языковые константы тем же образом. что и штатный плагин. А в массив $message помещаете данные для всех необходимых плейсхолдеров. Приведу пример из плагина логирования действий пользователей в админке компонента SW JProjects (GitHub).
<?php /** * After save content logging method. * This method adds a record to `#__action_logs` contains (message, date, context, user) * Method is called right after the content is saved * * @param string $context * @param object $item * @param bool $isNew * @param array $data * * @return void * * @since 2.4.0 // $context, $item, $isNew, $data * @todo use Model\AfterSaveEvent $event when Joomla 6 will be released */ public function onContentAfterSave($context, $item, $isNew, $data): void { // На момент выпуска релиза ещё немало сайтов было на Joomla 4, // поэтому из-за сохранения обратной совместимости с ней // используется ещё старый подход. // На новые рельсы перейдём после релиза Joomla 6 осенью 2025г. //$context = $event->getContext(); //$item = $event->getItem(); //$isNew = $event->getIsNew(); //$data = $event->getData(); // Массив с допустимыми контекстами для данного компонента if (!in_array($context, $this->contextList)) { return; } list($option, $contentType) = explode('.', $context); // Можно ли логировать данный компонент для конкретного юзера? if (!$this->checkLoggable($option)) { return; } // Новая сущность или редактируемая старая? if ($isNew) { $messageLanguageKey = 'PLG_ACTIONLOG_SWJPROJECTS_' . strtoupper($contentType) . '_ADDED'; $data['id'] = $item->id; } else if ($context == 'com_swjprojects.key' && $data['key_regenerate'] == 1) { $messageLanguageKey = 'PLG_ACTIONLOG_SWJPROJECTS_KEY_REGENERATED'; } else { $messageLanguageKey = 'PLG_ACTIONLOG_SWJPROJECTS_' . strtoupper($contentType) . '_UPDATED'; } // Для получения title отдельный метод, так как в компоненте не стандартная мультиязычность $message = [ 'action' => $isNew ? 'add' : 'update', 'type' => 'PLG_ACTIONLOG_SWJPROJECTS_TYPE_' . strtoupper($contentType), 'id' => $item->id, 'title' => $this->getItemTitle($context, $data), 'itemlink' => 'index.php?option=com_swjprojects&task=' . $contentType . '.edit&id=' . $item->id, ]; // В случае необходимости можно использовать любое количество // плейсхолдеров для замены. // Добавляем здесь нужные для нужных контекстов. if (!in_array($contentType, ['project', 'category', 'key'])) { $message['projectTitle'] = $this->getProjectTitle($item->project_id); $message['projectLink'] = 'index.php?option=com_swjprojects&task=project.edit&id=' . $item->project_id; } $this->addLog([$message], $messageLanguageKey, $context); }
В этом примере видно, что для некоторых контекстов (категория, проект и лицензионный ключ) нам не хватает стандартных значений и мы добавляем свои. Языковые константы выглядят следующим образом:
; Добавление документации для цифрового проекта PLG_ACTIONLOG_SWJPROJECTS_DOCUMENT_ADDED="Пользователь <a href=\"{accountlink}\">{username}</a> создал документацию <a href=\"{itemlink}\">{title}</a> для проекта <a href=\"{projectLink}\">{projectTitle}</a> в компоненте SW JProjects" ; Добавление лицензионного ключа PLG_ACTIONLOG_SWJPROJECTS_KEY_ADDED="Пользователь <a href=\"{accountlink}\">{username}</a> создал лицензионный ключ id <code>{title}</code> в компоненте SW JProjects" ; Работа с версиями программного обеспечения PLG_ACTIONLOG_SWJPROJECTS_VERSION_PUBLISHED="Пользователь <a href=\"{accountlink}\">{username}</a> опубликовал версию <a href=\"{itemlink}\">{title}</a> для проекта <a href=\"{projectLink}\">{projectTitle}</a> в компоненте SW JProjects" PLG_ACTIONLOG_SWJPROJECTS_VERSION_TRASHED="Пользователь <a href=\"{accountlink}\">{username}</a> переместил в корзину версию <a href=\"{itemlink}\">{title}</a> для проекта <a href=\"{projectLink}\">{projectTitle}</a> в компоненте SW JProjects"
Так это выглядит в панели администратора.

Дополнительные детали
Метод checkLoggable()
Конструктор класса плагина обычно выглядит следующим образом:
<?php /** * Constructor. * * @param DispatcherInterface $dispatcher The dispatcher * @param array $config An optional associative array of configuration settings * * @since 2.4.0 */ public function __construct(DispatcherInterface $dispatcher, array $config) { parent::__construct($dispatcher, $config); $params = ComponentHelper::getComponent('com_actionlogs')->getParams(); // Массив с системными именами логируемых компонентов $this->loggableExtensions = $params->get('loggable_extensions', []); // То же самое для REST API $this->loggableApi = $params->get('loggable_api', 0); // Логируемые методы REST API $this->loggableVerbs = $params->get('loggable_verbs', []); }
А сам метод проверки выглядит так:
<?php /** * Function to check if a component is loggable or not * * @param string $extension The extension that triggered the event * * @return boolean * * @since 2.4.0 */ protected function checkLoggable(string $extension): bool { return in_array($extension, $this->loggableExtensions); }
Заключение
Иногда сохранённые логи действий пользователей помогают быстрее найти решение проблемы, если она вызвана человеческим фактором. Да, может быть не всё удобно с точки зрения удобства использования и поиска, но это Open Source и это в составе ядра Joomla.
Надеюсь, мне удалось понятно изложить эту тему и по этой статье можно будет быстро внедрить нужный функционал в ваши компоненты Joomla.
Аргументированные замечания и предложения с радостью приму в комментариях.
Полезные ресурсы
Ресурсы сообщества:
-
https://vc.ru/s/1146097-joomla — Сообщество Joomla на VC.
Telegram:
Мой личный Telegram-канал — WebTolkRu.
ссылка на оригинал статьи https://habr.com/ru/articles/900338/
Добавить комментарий