Приветствую, коллеги!

Хочу представить вам плагин Joomla Shortcoder, который я разработал, чтобы упростить работу с шорткодами в Joomla.

И, так как в Joomla шорткоды широко не применяются, на всякий случай проясню что это такое.

Шорткод (англ. shortcode — короткий код) — это удобный способ добавить в текст статьи динамический контент или сложные HTML-элементы, не захламляя редактор громоздким кодом. Вместо того чтобы вставлять, скажем, полноценный <iframe> с кучей параметров, вы используете короткий и понятный тег.

Классический пример — вставка видео из YouTube в WordPress. Традиционный код выглядит примерно так:

<iframe
    src="https://www.youtube.com/embed/kBddBRQ-xic"
    width="560"
    height="315"
    allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
    title="YouTube video player"
    referrerpolicy="strict-origin-when-cross-origin"
    frameborder="0"
    allowfullscreen>
</iframe>

С шорткодом всё это превращается в одну строку:

[youtube https://www.youtube.com/watch?v=dQw4w9WgXcQ width="560" height="315"]

В Joomla тоже есть несколько встроенных шорткодов, например:

  • {loadmoduleid 123}: загружает модуль по ID;

  • {loadposition sidebar}: выводит модули из заданной позиции;

  • {field 5}: вставляет значение произвольного поля материала.

Однако WordPress, в отличие от Joomla, позволяет легко добавлять собственные шорткоды при помощи функции add_shortcode(), которую можно прописать в functions.php текущей темы или в MU-плагине.

Типичный вариант выглядит так:

add_shortcode('current_year', fn () => date('Y'));

После этого в любом посте будет работать конструкция [current_year], заменяясь на текущий год.

В Joomla для создания собственного шорткода вам придётся:

  1. Создать полноценный плагин группы content с XML-файлом манифеста.

  2. Установить его и активировать (можно через php cli/joomla extension:discovery).

  3. Подписаться на событие onContentPrepare.

  4. Написать регулярное выражение для поиска вашего тега.

  5. Обработать текст статьи при помощи preg_replace_callback().

  6. И, возможно, что-то ещё…

Это не самый простой путь, особенно если вам нужно всего лишь вывести текущую дату.

Среди расширений есть, например, JShortcodes с drag-and-drop интерфейсом или Easy Shortcodes на базе INI-файлов. Первый, на мой взгляд, перегружен сотнями виджетов и платный, второй — использует ini-файлы там, где естественнее писать на PHP.

Мне больше всего нравится Snippets от Regular Labs, но в нём также нет поддержки PHP.

Shortcoder использует другой подход. Никакого сложного визуального интерфейса: все шорткоды описываются прямо в PHP-файлах или задаются как вызываемые объекты (обычно это функции). Плагин автоматически подхватывает файлы из папки /shortcodes и превращает их имена в одноимённые теги.

Вот как можно просто создать шорткод для текущего года.

Для этого мы создаём файл shortcodes/current_year.php с содержимым:

<?php \defined('_JEXEC') or die;

// Весь вывод файла попадает в {current_year}

echo date('Y');

Теперь в любой статье можно написать {current_year} — и увидеть актуальный год.

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

<?php // shortcodes/shortcodes.php

\defined('_JEXEC') or die;

// Файл должен возвращать массив с шорткодами

return [
    // {current_year}
    'current_year' => fn () => date('Y'),

    // {hello "John Doe"}
    'hello' => fn (array $attributes) =>
        sprintf('Hello, %s!', $attributes[0] ?? 'World'),
];

А вот пример более сложного шорткода {details} для вставки спойлера. Здесь используется именованный атрибут summary и специальная переменная $content для получения содержимого внутри тега:

<?php // shortcodes/details.php

\defined('_JEXEC') or die;

$summary = $attributes['summary'] ?? 'Click to see more';
?>

<details>
    <summary><?php echo htmlspecialchars($summary); ?></summary>
    <div>
        <?php echo $content; ?>
    </div>
</details>

Использование в редакторе:

{details summary="Важная информация"}
Здесь скрытый текст, который увидит пользователь после клика.
{/details}

Надеюсь, я смог передать основную идею плагина.

Установка

Системные требования:

  • Joomla 4 и выше.

  • PHP 7.4 и выше.

Установка стандартная — скачиваете zip-файл с последней версией с GitHub Releases и устанавливаете через панель администратора: «Система» → «Установка» → «Расширения».

Можно использовать CLI:

php cli/joomla.php extension:install https://github.com/PopArtDesign/joomla-shortcoder/archive/refs/tags/v1.0.0.zip

После установки активируйте плагин «Content - Shortcoder» в менеджере плагинов.

Затем создайте директорию shortcodes в корне вашего сайта (там же, где лежат файлы Joomla). Любой php-файл из этой папки автоматически становится одноимённым шорткодом. Загружать и править файлы можно любым удобным способом — через FTP, файловый менеджер хостинга или даже прямо из админки, если используется компонент для редактирования файлов.

mkdir shortcodes && touch shortcodes/shortcodes.php

Синтаксис шорткодов

Шорткоды добавляются в текст при помощи тегов, заключённых в фигурные скобки: {foo}, {bar}, {baz} и т.д. В качестве имени тега может использоваться любая строка, содержащая буквы латинского алфавита, цифры, символы тире и нижнего подчёркивания.

Шорткоды бывают двух типов:

  • самозакрывающиеся: {hello "John Doe"}

  • с закрывающим тегом: {repeat 10}Repeat Me{/repeat}

Последние используются для захвата внутреннего содержимого, которое будет доступно в переменной $content:

<?php // shortcodes/shortcodes.php

\defined('_JEXEC') or die;

return [
    // {repeat 5}Hello, World!{/repeat}
    'repeat' => fn (array $attributes, string $content) =>
        str_repeat($content, (int) ($attributes[0] ?? 1))
];

Атрибуты

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

Атрибуты также бывают двух типов:

  • позиционные — перечисляются через пробел и доступны по индексу в массиве: $attributes[0], $attributes[1] и т.д.

    Пример: {hello John Doe}:

    • $attributes[0] = 'John'

    • $attributes[1] = 'Doe'

  • именованные — записываются в формате ключ="значение". Внутри обработчика шорткода они доступны по имени ключа: $attributes['key'].

    Пример: {hello first="John" last="Doe"}:

    • $attributes['first'] = 'John'

    • $attributes['last'] = 'Doe'

Все атрибуты передаются в обработчик в виде единого массива $attributes.

Также существует специальный атрибут _ (нижнее подчёркивание), который содержит только позиционные атрибуты в виде индексированного массива:

<?php // shortcodes/shortcodes.php

\defined('_JEXEC') or die;

return [
    // {sum 1 2 3 4}
    'sum' => fn (array $attributes) => array_sum($attributes['_']),
];

Значения атрибутов можно заключать в “двойные” или ‘одинарные’ кавычки. Если значение не содержит пробелов и специальных символов, кавычки можно опустить.

  • {button url="https://example.com" label="Click me"}

  • {button url=https://example.com label=Click} — валидно, но нужно помнить: значения без кавычек обрезаются первым же пробелом.

Переменная $item

В специальную переменную $item передаётся текущий объект публикации: статья, категория или другой элемент, который обрабатывается плагином. Это позволяет шорткоду взаимодействовать с контекстом, например, получать значения пользовательских полей (custom fields).

Вот пример шорткода, который выводит значение произвольного поля по его имени, а не по ID (в отличие от встроенного {field}):

<?php // shortcodes/shortcodes.php

\defined('_JEXEC') or die;

return [
    // Пример: {jcfield price raw="false"}
    'jcfield' => function (array $attributes, string $content = '', $item = null) {
        $name = $attributes['name'] ?? $attributes[0] ?? '';

        // Вообще говоря, свойство $item->jcfields может отсутствовать,
        // и лучше делать загрузку с помощью FieldsHelper
        if (!$name || !$item || empty($item->jcfields ?? null)) {
            return '';
        }

        // Выводить "сырое" значение?
        $raw = ($attributes['raw'] ?? 'true') === 'true';

        foreach ($item->jcfields as $field) {
            if ($field->name === $name) {
                return $raw ? $field->rawvalue : $field->value;
            }
        }
        return '';
    },
];

Вложенность

Шорткоды могут вкладываться друг в друга, но есть одно ограничение: не поддерживаются вложенные одноимённые теги.

✅ Работает:

{outer}
    {inner}Текст{/inner}
{/outer}

❌ Не работает:

{details}
    {details}Вложенный спойлер{/details}
{/details}

Это связано с ограничениями парсера, использующего регулярные выражения. Если кратко, регулярные выражения (конечные автоматы) «не умеют считать» и могут найти либо самый первый закрывающий тег, либо самый последний (жадный вариант). Если выбрать первый вариант — теряется поддержка вложенности, если второй — поддержка соседних тегов. Первый вариант мне показался более предпочтительным.

GitHub Gist

Напоследок давайте сделаем ещё один пример шорткода {gist} для вставки содержимого GitHub Gist:

<?php // shortcodes/gist.php

\defined('_JEXEC') or die;

// Получение URL для вставки
if (!$url = $attributes[0] ?? '') {
    // URL не был передан: {gist}, можно ничего не выводить
    return;
}

if (strpos($url, 'https://gist.github.com') !== 0) {
    // Был указан некорректный адрес: {gist https://gitflic.ru}
    return;
}

$scriptUrl = rtrim($url, '/') . '.js';

// Имя файла: {gist url file="somefile.php"}
if ($file = $attributes['file'] ?? '') {
    $scriptUrl .= '?file=' . urlencode($file);
}
?>
<script src="<?php echo htmlspecialchars($scriptUrl); ?>"></script>

Использование:

{gist https://gist.github.com/voronkovich/d35cdcdf6eb09e986ab9b16f91a5b2e8}

{gist https://gist.github.com/voronkovich/d35cdcdf6eb09e986ab9b16f91a5b2e8 file=somefile.php}

Более подробную документацию по работе с плагином вы можете прочитать в репозитории проекта.

Благодарю за внимание!

P.S. Несколько полезных замечаний от @progreccor:

  1. Всегда добавляйте инструкцию \defined('_JEXEC') or die;. Это стандарт Joomla, предотвращающий прямой доступ к файлу по URL.

  2. Не давайте доступ к папке /shortcodes редакторам и контент-менеджерам. Эта директория предназначена только для разработчиков.

  3. Если используете Apache, добавьте в .htaccess директиву:

    <Directory "/shortcodes">
        Require all denied
    </Directory>
    
  4. При включённом кэше значения шорткодов также будут кэшироваться. Соответственно, динамические значения не будут обновляться. Например, {current_date} будет выводить одно и то же значение пока кэш не будет сброшен. С другой стороны, для большинства шорткодов (iframe, {gist url} и т.д.) это будет не критично.

  5. Для простых констант и функций - используйте Revars.

Комментарии (2)


  1. Sulpher
    02.05.2026 14:22

    Хорошее решение. На Joomla 6 работает нативно?


    1. voronkovich Автор
      02.05.2026 14:22

      Да, работает. Изначально делал под один из текущих проектов на php 7.4 и Joomla 4. Потом добавил подержку других верисий 5 и 6 (для плагинов там минимальное отличие в API).