В продолжнении моей статьи, опубликованной в сообществе MODX, я хочу привести примеры того, как собственные теги упрощают вёрстку сайта. В документации к Fenom написано:

В шаблонизаторе принято различать два типа тегов: компиляторы и функции. Компиляторы вызываются во время преобразования кода шаблона в PHP код и возвращают PHP код который будет вставлен вместо тега. А функции вызываются непременно в момент выполнения шаблона и возвращают непосредственно данные которые будут отображены. Среди тегов как и в HTML есть строчные и блоковые теги.

С компиляторами познакомиться пока не пришлось, а функции уже использую для вывода картинок. У меня несколько разделов на сайте — документация, дополнения, блог. И в каждом из них у меня есть какие-то картинки — изображение дополнения, скриншот экрана и т.п. Одни выводятся просто картинкой, другие ссылкой для fancybox. Для каждого раздела определено своё место для хранения картинок.

Особенно трудоёмкая задача вывести картинку для fancybox. При создании новой статьи приходилось открывать статью, где использовался fancybox, и копировать код ссылки, править названия файлов. В конце концов я создал чанк, в котором прописал весь код, и вызывал его.

// Код чанка
<a class="fancybox" rel="fancybox" href="[[+image]]">
    <img src="[[+thumb]]" class="img-responsive thumbnail center">
</a>

И вызывал на странице с параметрами — имя файла и миниатюры:

// Сначала так
[[$fancybox? image=`url/to/file/file.jpg` &thumb=`url/to/file/file_thumb.jpg`]]
// Затем переделал на файловый чанк
{'@FILE fancybox.tpl' | chunk : ['image' => 'url/to/file/file.jpg', 'thumb' => 'url/to/file/file_thumb.jpg']}

Так стало значительно проще. Но возможность создавать собственные теги делает это ещё элегантнее и легче. Нужно всего лишь один раз создать плагин, прописать необходимую логику и наслаждаться творчеством вместо рутины.

// Плагин
switch ($modx->event->name) {
    case 'pdoToolsOnFenomInit':
        $fenom->addFunction("fancyboxImage", function (array $params) {
            // Формируем путь к файлу
            $file = MODX_ASSETS_URL . 'images/' . $params[0];
            $thumb = $params[1] ? MODX_ASSETS_URL . 'images/' . $params[1] : $file;
            $output = '<a class="fancybox" rel="fancybox" href="' . $file . '"><img src="' . $thumb . '" class="img-responsive thumbnail center"></a>';
            return $output;
        });
        break;
}

Теперь, чтобы вставить картинку, нужно указать новый тег и два параметра:

{fancyboxImage 'file.jpg' 'file_thumb.jpg'}

Согласитесь, это пострясающе. Лично я создал ещё несколько тегов — fancyboxDocImage для картинок документации и fancyboxBlogImage для картинок статей, которые отличаются только путями к файлам. Кроме того, исключилась операция чтения чанка с диска. Что тоже положительно сказывается на времени загрузки.

Таким же образом можно выводить, например, первую картинку в статье — {firstArticleImage}. Или случайную картинку. Или несколько картинок в одном блоке.

В общем, применений можно найти много. Присмотритесь, может есть чанки и сниппеты, которые вы можете легко заменить.

17 сентября 2017, 18:14   838     11

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

  1. Семён 20 сентября 2017, 15:41 # 0
    Сергей, спасибо за статью, с удовольствием читаю Ваш блог.
    Возник вопрос — при создании собственных тегов, почему-то нельзя их вызвать без параметра из контента ресурса, просто выводится сама конструкция {tag} а не то, что она должна возвращать.
    Когда этот же тег без параметров запускаешь из кода шаблона — нет проблем, всё отрабатывает как надо.
    Хотел сделать возможность на сайте вставлять прямо в контент ресурса конструкции типа {googlemap}, который без параметров проверит тв-шку ресурса и если там есть что вывести, то покажет карту.
    Вставляю этот тег в код шаблона — карта выводится. Вставляю в контент ресурса — получаю {googlemap}
    У Вас в статье написано — «Таким же образом можно выводить, например, первую картинку в статье — {firstArticleImage}»
    Возникает вопрос, а отработает ли этот тег находясь в поле контент ресурса?
    P.S Нашёл решение проблемы, но оно мне совсем не нравится — просто передаю тегу в качестве параметра пустую строку и тогда всё работает! Но выглядит это так — {googlemap ''}
    Возможно ли как то это обойти?
    1. Сергей Шлоков 20 сентября 2017, 15:57 # 0
      Возникает вопрос, а отработает ли этот тег находясь в поле контент ресурса?
      У меня все теги в ресурсе указаны, и с параметрами и без, ошибок нет. Проверьте лог. Раз выводится необработанный тег, то возможно возникает какая-то ошибка. Попробуйте удалить параметр $params из функции —
      $fenom->addFunction("googlemap", function (array $params) { // Удалите аргумент 
      
      1. Семён 20 сентября 2017, 16:14 # 0
        Попробовал удалять аргумент, не работает, в логах чисто, как будто он как простую строку этот тег воспринимает, когда она без параметра.
        Вот набросал пример на modhost — такая же проблема!
        Доступы:
        s11046.h5.modhost.pro/manager/
        s11046
        rP3DJyD6IB42
        1. Сергей Шлоков 20 сентября 2017, 16:36 # +1
          Известная проблема или особенность фенома.
          1. Семён 20 сентября 2017, 16:41 # 0
            Спасибо, жаль, я уж обрадовался своим тегам…
            1. Семён 20 сентября 2017, 16:51 # 0
              Получилось решить проблему простым добавлением пробела перед закрывающей фигурной скобкой.
              1. Сергей Шлоков 20 сентября 2017, 16:59 # +2
                Проблема вот в чем — pdoTools запускает парсер Fenom только если есть хоть один тег, который начинается с символов: $, (, /, слова и пробела. Вот регулярка. Вариант решения — указать в системной настройке pdotools_fenom_syntax свой синтаксис, разрешающий вызов собственных тегов. Как минимум удалить \s из регулярки.
      2. Семён 06 января 2018, 13:42 # 0
        Приветствую, Сергей.
        Возник вопрос по поводу добавлению собственных тегов с использованием компонента Middleware
        Я создал обработчик события — myTags подключил его в системных настройках.
        Внутри реализовал метод по названию события pdoToolsOnFenomInit
        public function pdoToolsOnFenomInit()
            {
                $fenom->addFunction('mytag', function () {
                    $output = '<div class="my-super-class">This is my super Tag</div>';
                    return $output;
                });
            }
        
        Но такой тег не добавляется в систему, переношу данный код в обычный плагин и всё работает.
        Пробовал указывать контексты выполнения, порядок срабатывания — не получается.
        Подскажите, пожалуйста, в чём может быть проблема?
        1. Сергей Шлоков 07 января 2018, 08:58 # 0
          Проблема в невнимательности. Откуда взялся объект $fenom? Его нужно получить. Для этого есть 2 способа:
          # 1. Обратиться к объекту pdoTools.
          $fenom = $this->modx->getParser()->pdoTools->getFenom();
          
          #2. Получить из передаваемых параметров.
          public function pdoToolsOnFenomInit($properties)
          {
              $fenom = $properties['fenom'];
              $fenom->addFunction('mytag', function () {
                  $output = '<div class="my-super-class">This is my super Tag</div>';
                  return $output;
              });
          }
          
          В документации есть пример с использованием функции extract.
          1. Семён 07 января 2018, 10:17 # 0
            Огромное спасибо, Серей.
            1. Сергей Шлоков 07 января 2018, 10:26 # 0
              На здоровье!

              Совет. Чтобы не лазить каждый раз в админку для подключения обработчиков событий используйте посредник InitMiddlware, который подключается из коробки. В нём даже есть пример подключения обработчика test.

        Вы должны авторизоваться, чтобы оставлять комментарии.

        Выделите опечатку и нажмите Ctrl + Enter, чтобы отправить сообщение об ошибке.