Создание шаблонов сайта в Joomla 4+

Моя цель - предложение широкого ассортимента товаров и услуг на постоянно высоком качестве обслуживания по самым выгодным ценам.

Ранее на Хабре были опубликованы статьи Создание модулей с учётом новой структуры Joomla 4, Создание плагинов с учётом новой структуры Joomla 4, где освещались нюансы по апгрейду расширений до архитектуры Joomla 4 / Joomla 5. А также статья Создание плагина кнопки редактора в Joomla 4, в которой в том числе затрагиваются вопросы распределения функционала между фронтом и бэком, приводится практический пример работы с ajax нативными для Joomla средствами. Однако, расширение типа template, пожалуй, создаётся для сайтов на Joomla чаще, чем другие типы расширений.

Оглавление статьи

  • Вступление

  • Обзор литературы

  • Определение логической структуры страниц

    • Маркетинг

    • UI/UX и дизайн

    • Вёрстка

    • Взаимодействие с backend

  • Определение типа расширения Joomla для элементов страницы

    • Какие типы расширений Joomla существуют?

    • Собственно определение типов расширений Joomla при создании шаблона.

    • Если бы Хабр был сделан на Joomla.

  • Сущность шаблона. Отличия шаблонов Joomla 4 и Joomla 5 от шаблонов Joomla 3

  • Файловая структура шаблона Joomla 4 и Joomla 5

    • Файл templateDetails.xml

    • Файл index.php

      • Условия для вывода позиций внутри шаблона

    • Файл component.php

    • Файл error.php

    • Файл fatal.php

    • Файл offline.php

    • Файл joomla.asset.json

  • Дочерние шаблоны (дочерние темы) в Joomla

  • Шаблоны с опциями (добавить настройки для своего шаблона)

  • Сущность модуля. Дизайн для модулей на Joomla-сайте.

    • Макет модуля Joomla. Переопределения.

    • Суффикс класса модуля (CSS-класс модуля)

    • Chrome модуля (стиль модуля) Joomla

    • Применение стилей модуля в Joomla

    • Способы вставки модулей

  • Сущность плагина Joomla в аспекте вёрстки шаблона

    • Макеты вывода плагинов Joomla, Переопределение.

  • Сущность компонента Joomla в ракурсе создания шаблона сайта

    • Канонический способ размещения макетов компонента

    • Неканонический способ размещения макетов компонента

      • Virtuemart, JoomShopping

  • Сущность лейаутов (Joomla Layouts). Переопределение.

  • Скорость загрузки сайта Joomla и 100 зелёных попугаев

  • Общие рекомендации

  • Заключение

Вступление

Нужно признать, что Joomla предоставляет довольно большой функционал из коробки, путей решения одной и той же задачи может быть несколько и бывает сложно назвать какой-либо из них однозначно правильным. Разные разработчики являются приверженцами разных подходов, что порой вызывает жаркие споры между ними.

С Joomla работают как начинающие веб-мастера, так и профессиональные команды. В руках разработчика шаблона для Joomla может оказаться как только FTP, Notepad++ и шаблон-билдер, так и и профессиональные среды разработки (PHP Storm / VS Code). Существуют команды, где Joomla обитает в условиях CI/DI, Git, тестовых стендов и прочим. А бывают и условия, когда изменения вносятся прямо на прод (production, боевой сайт) и он падает прямо на глазах у посетителей. Поднимается и снова падает, и снова поднимается... Соответственно конечный результат работы вебмастера, разработчика может быть совершенно разный и мы понимаем, что не инструмент красит человека, а умелые руки - инструмент.

Определенную нишу занимают шаблоны-билдеры, а-ля Helix Ultimate (+ SP Page Builder) от JoomShaper, YooTheme PRO, Astroid (Templazza), T4 (JoomlaArt), Gantry и другие. Работа с ними несколько отличается от классических шаблонов, так как предполагает создание своих элементов для билдеров и в целом содержит немалую долю работы с интерфейсом. Этот подход имеет свою аудиторию и право на жизнь. Однако, приобретая в скорости разработки шаблона нередко приходится жертвовать качеством HTML-кода. В нём могут появляться лишние div-обёртки и мусорный код, которых можно было бы избежать. В данной статье шаблоны-билдеры если и будут затрагиваться, то косвенно.

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

В данной статье я постараюсь сместить акцент с вектора "как создать шаблон для Joomla 4 и старше" на "какие возможности даёт Joomla 4 при разработке шаблона и для уникализации страниц". Использовать или нет и как использовать определённые возможности Joomla для создания шаблона сайта - решать уже Вам.

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

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

Обзор литературы

Из статей-мануалов на Хабре можно выделить серию статей Создаём шаблон Joomla по стандартам (часть 1) 2008 года - ещё для Joomla 1.5. Статью Как сверстать шаблон для Joomla 2015 года, где на скриншотах видна Joomla 3.4.1. А также статья Дизайн шаблона Joomla для front-end разработчика совершенно незнакомого с CMS 2014 года, которая показалась мне самой лаконичной и дельной из всех представленных на Хабре.

К сожалению, официальная документация Joomla по созданию шаблона на момент написания статьи приводит примеры для Joomla 1.5-2.5 и большая её часть на данный момент является уже устаревшей.

Новый портал документации Joomla пока ещё на стадии наполнения. На момент написания этой статьи о шаблонах там заполнена лишь некоторая информация.

Подавляющую часть сил активная часть сообщества бросает на работу с кодом ядра, поэтому актуальная документация - это больная мозоль. Постараемся от неё избавиться в этой статье.

Из современных недавних текстов, посвящённых уже Joomla 4 можно отметить статью Developing a Joomla Template" Кевина Олсона (Kevin Olson). Нужно отдать автору должное, периодически он обновляет содержимое статьи. На том же сайте в категории статей Joomla Templates есть ещё несколько полезных текстов о разработке шаблонов Joomla.

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

Определение логической структуры страниц

Для каждой страницы сайта важна верно сконструированная в нескольких плоскостях логика: маркетинг, UI/UX, дизайн, верстка, взаимодействие с бэком.

Маркетинг

Здесь мы подразумеваем то, что страница в целом должна обеспечить пользователю максимально быстрое и удобное продвижение по пути к совершению целевого действия (продвижение по customer jorney). Для разных типов страниц это разные целевые действия: для одних это может быть переход на другую страницу, для других - нажатие кнопки, обращение в живой чат, заполнение формы, долгое время нахождения на странице, просмотр попапа (всплывающего окна) и т.д. Распределением по страницам целевых действий занимается не верстальщик или вебмастер, но он должен понимать что должна страница сайта предоставить пользователю.

UI/UX и дизайн

Я позволю себе объединить их в один раздел эти специфичные, хоть и во многом близкие по целям, области. Грамотный UI/UX с помощью дизайна является той логикой и в чём-то механикой продвижения посетителя сайта к целевому действию. Именно UI/UX специалисты в купе с дизайнерами помогают нам быстро ориентироваться на странице, находить нужные кнопки и радоваться работе с приятным интерфейсом.

Верстка

Казалось бы зачем всё вышесказанное знать верстальщику? Причем тут код? Но знание того, что должно, например, отобразиться на сайте быстрее и начать работать быстрее (в случае активных элементов) позволит выстроить правильный порядок загрузки скриптов. Или не помещать в карусель изображений на первый экран 100500 картинок, так как пользователи пролистают от силы 2-3 и уйдут вниз по странице или вообще на другую страницу. Те же знания о UI/UX и важных целевых действиях позволят правильно расставить атрибуты loading="lazy" изображениям (а не всем подряд) и т.д. и т.п.

Семантическая верстка

На эту тему написаны тонны текстов. Joomla начиная с версии 3.0 имеет возможность использовать HTML5 теги для модулей - уже больше 10 лет. Но насколько редко этим функционалом пользуются! А ведь она нужна для передачи смысла поисковикам.

У вас контентный сайт, в статье покупают ссылки и размещают рекламные блоки. Для тех, кто покупает ссылки хорошо, чтобы они были максимально "нативно" внедрены в текст, в то время как для Вашего сайта важно не засорять тексты сильно, иначе поисковики вычленят купленные ссылки, могут пессимизировать сайта и он потеряет трафик, а вы - прибыль от рекламы. Таким образом, рекламную вставку внутри текста статьи Вы будете оформлять не тегом <div> или <section>, а тегом <aside>, семантическая роль которого в отделимом и не имеющем прямого отношения к основному тексту смысле. А если модуль с тегами статей в правой или левой колонке окажется в теге <aside>, то его семантическая полезность для страницы может быть утрачена, так как поисковик будет считать его содержимое не относящимся к основному смыслу страницы.

Таких деталей много: теги <strong> и <b>, теги <section> и <article>, обернуть вывод компонента в <main> (коих, кстати, может быть несколько на странице) и т.д. Семантическая вёрстка - это про умение грамотно понимать и выражать мысли, расставлять правильные акценты. У Joomla для этого есть все возможности.

Взаимодействие с backend сайта

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

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

Так, в примере с калькулятором, обработчик формы должен быть оформлен в виде плагина группы ajax. Но, если этот же плагин выполняет ещё какую-то работу, то группу для плагина можно выбрать и любую другую. Благо через ajax-интерфейс можно обратиться к любому плагину (лишь бы сам плагин поддерживал работу с ajax-интерфейсом). Также начиная с Joomla 4 в ядре есть REST API. При необходимости можно использовать и его.

Это вроде бы мелочи, о которых думают в последний момент или не думают вообще. Но при оценке стоимости и сроков проекта влияние подобных мелочей весьма ощутимо.

Определение типа расширения Joomla для каждого элемента страницы

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

Какие типы расширений Joomla существуют?

В Joomla существует 7 типов расширений (подробнее Типы расширений Joomla), из которых возможность вывода HTML имеют 4: компонент, модуль, плагин и шаблон.

Компонент (Component) - это самый сложный тип расширения в Joomla. Как правило он даёт возможность CRUD операций (создание, чтение, изменение и удаление данных в базе данных). Примеры компонентов: блог, каталог продукции, доска объявлений, социальная сеть, интернет-магазин, гостевая книга и т.д. В комплекте с компонентом часто идут плагины и модули, иногда библиотеки. В таком случае компонент и сопутствующие расширения собираются в пакет. Ядро Joomla содержит встроенные компоненты (например, для блога, управления пользователями и их правами доступа, контакты и т.д.) и может расширяться компонентами сторонних разработчиков (интернет-магазины, форумы, e-mail маркетинг и т.д.).

Модуль (Module) - расширение, которое чаще всего выводит данные из какого-либо компонента или собственных настроек, либо позволяет добавлять данные в какой-либо компонент. Пример модулей: слайдшоу изображений, карусель товаров, новые статьи, форма подписки на email-рассылку и т.д. Иногда функции модулей и компонентов могут пересекаться. Например, вывести интерактивную карту с гео-метками филиалов и контактов к ним можно с помощью как специализированного компонента, так и с помощью модуля; форму авторизации можно отобразить как с помощью компонента (отдельный пункт меню и страница на сайте), либо модулем (отобразит форму входа на всех страницах согласно настройкам модуля). Выбор конкретного способа зависит от решаемых задач.

Модули выводятся в позициях шаблона, которые задаются в файле index.php шаблона или же в том месте, где их вызывает шорт-код {loadposition ...} или {loadmoduleid 123}. Также есть продвинутый вариант рендера модулей программным методом с помощью класса ModulelHelper.

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

Общая информация о принципе действия Joomla

Полезно будет посмотреть статью Общая информация о принципе действия Joomla. Она описывает общий принцип действия Joomla, начиная с загрузки файла index.php и заканчивая отображением страницы в обозревателе. В статье рассматривается Joomla 3, однако большая часть верна и для Joomla 4.

Видов плагинов существует огромное количество. Они могут добавлять команды в CLI интерфейс, отправлять данные заказа в CRM и службу доставки, добавлять поля в интерфейс админки, обрабатывать и проверять данные в процессе их изменения и многое другое. Вызовы плагинов происходит в разные моменты жизненного цикла приложения Joomla.

Из их многообразия нас больше всего интересуют плагины группы content. Плагины этой группы чаще всего обрабатывают HTML код и заменяют в нём шорткоды вида {STARG_TAG}некий код{/END_TAG} или {ANY_TAG param=1 param2=2} на нужные Вам данные. Например, известный плагин All Videos заменяет теги {youtube}код_видео{/youtube} на код проигрывателя Youtube-видео, а {MP4}путь_к_файлу{/MP4} - на HTML5 тег <video> для указанного файла. Но таким образом могут вставляться и модули (шорт-код {loadposition position_name} или {loadmoduleid id}) и данные из других компонентов, если для них существуют контент-плагины (фотогалереи, товары, карусели и т.д.). С HTML-кодом часто работают плагины группы system на событие onAfterRender. В этом случае обработка HTML-кода происходит с помощью регулярных выражений PHP.

Шаблон (Template). Это тип расширения, в котором описывается HTML разметка для HTML-вывода сайта. В терминологии WordPress шаблон Joomla - это тема. У шаблона также могут быть свои параметры, логика вывода позиций для модулей и т.д. В шаблоне (но не только в нём) подключаются CSS, JS, иконки, шрифты и прочие Web Assets.

В файлах шаблона иногда хардкодятся костыли.

В целом, для того, чтобы правильно определить типы расширений Joomla для проекта нужно знать как минимум расширения ядра CMS и их возможности. В идеале на сайте должен быть минимум сторонних расширений, чтобы не зависеть от работы внешних разработчиков. У них может быть свой road map, который не пересекается с Вашим или впоследствии разработчик может забросить своё детище и Вам придётся искать альтернативы.

Собственно определение типов расширений Joomla при создании шаблона

Как я уже говорил, в Joomla одна и та же в целом задача может быть решена разными способами. Здесь нужно иметь ещё и некое видение наперёд: как будет развиваться проект, в какую сторону он будет развиваться и постараться предусмотреть наиболее вероятные пути его движения. В зависимости от этого Вы будете выбирать правильные расширения для сайта и с ними уже работать.

Так, каталог продукции можно сделать как на стандартных материалах Joomla (статья), так и на компоненте интернет-магазина, который будет работать в режиме каталога. Если Вы поговорили с клиентом и выяснили, что каталог останется каталогом, то можно использовать стандартные материалы. Из плюсов - Вы не зависите от сторонних расширений. А если же проект может "взлететь" до приёма оплаты, личного кабинета, интеграции с CRM, службами доставки и прочим, то лучше сразу использовать компонент интернет-магазина. Таким образом Вам легче будет работать с ним потом.

Перейдём, наконец, к практике.

Если б Хабр был сделан на Joomla

Возьмём для примера страницу просмотра статьи на Хабре и посмотрим как она устроена.

Условные обозначения:

  • T - template - в принципе это вся страница целиком. Но специально выделены те элементы, которые обычно выносятся в настройки шаблона (или порой хардкодятся).

  • C - component - область вывода компонента. Центральный, основной контент страницы.

  • M - module - "обвязка" основного контента из модулей с самым разным функционалом.

  • P - plugin - плагины. В данном примере действия плагинов похожи на модули, но плагины внедряются в то, что выводит компонент и добавляют в него свой HTML-вывод. Поскольку на уровне кода это может быть решено разными способами, то в этих случаях я указал знак вопроса: P ? M.

А что если Хабр сделан на Joomla?..
А что если Хабр сделан на Joomla?..

Несмотря на кажущуюся простоту страница просмотра статьи на Хабре имеет сложную структуру (и это только одна страница!). На ней более 10 разных типов модулей. На странице используются минимум 7 (скорее всего 8-10) позиций для модулей. Частично задействованы плагины. Но это могут быть тоже модули )). Всё зависит от конкретных расширений, которые Вы используете на сайте.

Сущность шаблона Joomla. Отличия шаблонов Joomla 4 и Joomla 5 от шаблонов Joomla 3

Кратко, описания изменений для опытных Joomla-разработчиков.

  1. Папка media для шаблона. Начиная с Joomla 4.1 все медиа-файлы (CSS, JS, шрифты, иконки и картинки и прочее) переехали в папку media/templates/site/template_name. Если шаблон пишете для админки Joomla, то всё помещаем в media/templates/administrator/template_name.

  2. Joomla 4 внедрила концепцию Web Assets. Управление JavaScript и CSS в Joomla значительно упростилось, благодаря классу WebAssetManager. Есть замечательная статья Как правильно подключать JavaScript и CSS в Joomla 4, в которой подробно и с примерами кода рассказывается об этой концепции и её применении. 
    Например, было: иконочный шрифт могут использовать 2 разных модуля. CSS обычно подключается в шаблоне и он грузится везде, даже там, где не надо. Если же подключать CSS в одном модуле, а в другом нет - на странице стиль есть ровно до тех пор, пока опубликован модуль с этим подключением.
    Стало: теперь в макетах расширений мы просто пишем $wa->useStyle('my.style'); и за необходимостью подключения нужного ассета (в данном случае CSS с иконочным шрифтом) следит Web Asset Manager. Если мы снимем один модуль с публикации, то нужный ассет подключит другой модуль. Также поддерживаются зависимости. Например, если какой-то js-скрипт требует jQuery (от чего сейчас избавляются, но всё же), то достаточно при подключении ассета своего скрипта указать в зависимостях jQuery и он подключится автоматически, даже если в других местах Вы его выключали. Для инлайн стилей есть возможность выстраивать порядок включения.

  3. Файл joomla.asset.json. Для того, чтобы можно было работать с WebAssetManager нужно создать файл joomla.asset.json и описать js, css шаблона в нём. Файл должен находиться в media/templates/site/template_name, рядом с самими ассетами.

  4. Дочерние шаблоны. Начиная с Joomla 4.3 есть возможность создавать дочерние шаблоны. Для того в XML-манифесте должен быть элемент <inheritable>1</inheritable>. Файлы дочернего шаблона переопределяют файлы родительского. То есть мы можем скопировать из родительского шаблона лишь некоторые файлы, которые мы хотим изменить, а в остальном будут использоваться файлы родительского шаблона.

Теперь опишем более подробно процесс работы с шаблоном.

Файловая структура шаблона Joomla 4 и Joomla 5

Во-многом архитектура шаблона в Joomla осталась такая же, как и раньше. Но кратко опишем её здесь для полноты статьи. Также в качестве справочного материала можно использовать стандартный шаблон Cassiopeia.

Файловая структура шаблона Joomla 4 и Joomla 5
Файловая структура шаблона Joomla 4 и Joomla 5

Минимум для создания шаблона нужно по-прежнему 2 файла:

  • templateDetails.xml - XML-манифест расширения. В нём содержится информация об авторе, дате создания, сервере обновлений (если есть), раздел с настройками и т.д.

  • index.php - основной файл, в котором содержится HTML-разметка шаблона.

Но мы устанавливаем Joomla 4 или Joomla 5 не для того, чтобы работать как 20 лет назад. Поэтому структура современного шаблона более сложная.

Файл templateDetails.xml

Содержимое этого файла во-многом аналогично XML-манифестам прочих расширений Joomla.

<?xml version="1.0" encoding="utf-8"?>
<extension type="template" client="site" method="upgrade">
	<name>webtolk</name>
	<version>1.0.0</version>
	<creationDate>April 2023</creationDate>
	<author>Sergey Tolkachyov</author>
	<authorEmail>info@web-tolk.ru</authorEmail>
	<copyright>(C) 2023 Sergey Tolkachyov.</copyright>
	<description>TPL_WEBTOLK_DESC</description>
	<inheritable>1</inheritable>
	<files>
		<filename>component.php</filename>
		<filename>error.php</filename>
		<filename>index.php</filename>
		<filename>joomla.asset.json</filename>
		<filename>offline.php</filename>
		<filename>templateDetails.xml</filename>
		<folder>html</folder>
		<folder>subform</folder>
	</files>
	<media destination="templates/site/webtolk" folder="media">
		<folder>js</folder>
		<folder>css</folder>
		<folder>fonts</folder>
		<folder>scss</folder>
		<folder>images</folder>
	</media>
	<positions>
		<position>topbar</position>
		<position>below-top</position>
		<position>menu</position>
		<position>search</position>
		<position>banner</position>
		<position>top-a</position>
		<position>top-b</position>
		<position>main-top</position>
		<position>main-bottom</position>
		<position>breadcrumbs</position>
		<position>sidebar-left</position>
		<position>sidebar-right</position>
		<position>bottom-a</position>
		<position>bottom-b</position>
		<position>footer</position>
		<position>debug</position>
	</positions>
	<languages folder="language">
		<language tag="en-GB">en-GB/tpl_webtolk.ini</language>
		<language tag="en-GB">en-GB/tpl_webtolk.sys.ini</language>
		<language tag="ru-RU">ru-RU/tpl_webtolk.ini</language>
		<language tag="ru-RU">ru-RU/tpl_webtolk.sys.ini</language>
	</languages>
	<config>
		<fields name="params">
			<fieldset name="basic">
				<!-- тут параметры шаблона -->
			</fieldset>
		</fields>
	</config>
</extension>

Я опущу интуитивно понятные элементы и опишу только самые необходимые.

Элемент <name> - это системное имя шаблона, под которым Joomla будет знать этот шаблон. Также это имя папки шаблона, в которую он будет установлен в папке templates. Если в имени содержатся пробелы и другие символы - для системных нужд они будут удалены. В админке же Вы будете видеть красивое имя вида "My Digital Agency - Cool Template name".

Элемент <inheritable> нужен для возможности создания дочерних шаблонов. Чуть выше описано как это работает.

Элемент <description> - краткое описание расширения. Тут можно писать сразу текст или использовать языковую константу из языковых файлов шаблона. Аналогичный подход и к параметрам шаблона.

Элемент <files>. Здесь мы указываем список копируемых файлов и папок шаблона. Если физически файл будет установочном пакете, но не описан в XML-манифесте - он не будет скопирован. Если файл будет описан, но физически его не будет в установочном пакете - будет ошибка установки шаблона.

Элемент <media>. О нём кратко сказано выше (о концепции Web Assets). Он сообщает какие папки нужно поместить в папку media сайта. Атрибут destination="templates/site/webtolk" указывает путь от папки media, атрибут folder="media" говорит из какой папки в установочном архиве нужно брать файлы и папки для копирования.

Элемент <positions> - это список позиций для модулей, который Ваш шаблон поддерживает. Эти позиции оказываются в выпадающем списке в настройках модулей.

Список позиций для модулей, которые поддерживает шаблон
Список позиций для модулей, которые поддерживает шаблон

Но никто не мешает Вам в этом поле ввести вручную имя позиции, не описанной в XML-манифесте и в index.php (или шорткодом lв материалах или программно где угодно) вызвать эту позицию и модули волшебным образом появятся там, где нужно. Это очень помогает, когда нужно вставить условную форму захвата контакта или какой-нибудь другой модуль прямо в середину статьи. Придумываем несуществующую доселе позицию, пишем её в настройках модуля (нажимаем Enter) и знаем, что эта позиция используется только в одном конкретном месте. Важно понимать, что позиции для модулей легко добавляются на лету. Не нужно каждый раз редактировать XML-манифест шаблона. Хотя это правильный путь, но так редко делают. Обычно в XML-манифесте описаны часто используемые, универсальные позиции.

Элемент <languages> содержит описания языковых файлов для шаблона. Если пользователи админки из разных стран или Вы планируете распространять свой Joomla шаблон в разных странах, то полезно сделать файлы локализации. Если же не планируете, то можно на первое время захардкодить описания, текст прямо в XML.

Но:

  1. Нужно всё равно сделать языковые константы, чтоб был порядок на сайте.

  2. В языковые константы можно помещать HTML, предварительно экранировав кавычки атрибутов. Тогда Вы можете делать информативные описания со ссылками, картинками и т..д. Можно хоть видео с Youtube вставлять.

Секция <config> нужна для шаблонов, у которых есть настраиваемые параметры. Подробнее об этом ниже.

Файл index.php шаблона Joomla 4

Здесь находится HTML-каркас вёрстки Joomla сайта. Базовой для создания шаблона вещью является конструкция <jdoc:include type="тут тип"/>. Самый простой index.php может выглядеть следующим образом:

<?php
// No direct access to this file
defined('_JEXEC') or die;
?>

<!DOCTYPE html>
<html>
<head>
  <!-- В Joomla 3 был только type="head". 
  В Joomla 4 можно быстро перенести скрипты и стили в подвал сайта, 
  без всяких плагинов -->
	<jdoc:include type="metas"/>
	<jdoc:include type="styles"/>
	<jdoc:include type="scripts"/>
</head>

<body>
<nav>
<jdoc:include type="modules" name="menu"/>
</nav>
<main>
<jdoc:include type="component"/>
</main>
</body>
</html>

Обратите внимание, что здесь совсем нет PHP-кода, но данный шаблон уже будет работать. defined('_JEXEC') or die не в счёт, так как это стандартная проверка безопасности Joomla, не позволяющая обращаться к файлу "снаружи", минуя Joomla API. Эта строка должна быть абсолютно в любом PHP-файле в Joomla, в самом начале. Если в файле есть секция подключения namespaces - use \Joomla\CMS\Factory например - строка defined... должна идти сразу после неё.

<jdoc:include type="modules" name="menu"/> - выведет в данном месте HTML, который отдают модули в позиции menu. Также может быть ещё 3-й параметр style, который означает выбранный chrome (обёртку) для модуля - <jdoc:include type="modules" name="menu" style="xhtml"/>. Подробнее об этом будет сказано ниже.

Также спецификация HTML5 требует, чтобы у тега <html> были указаны параметры языка и направления чтения. Joomla предоставляет эти данные для шаблона. Тег <html> будет выглядеть следующим образом:

<html lang="<?php echo $this->language; ?>" dir="<?php echo $this->direction; ?>">

Условия для вывода позиций внутри шаблона

При работе с сайтом, чтобы узнать какие модульные позиции существуют в шаблоне нужно в Система - Шаблоны - кнопка "Настройки" включить параметр "Просмотр позиций модулей". Не забудьте его выключить после окончания работ с шаблоном сайта.

параметр "Просмотр позиций модулей" в настройках менеджера модулей Joomla 4
параметр "Просмотр позиций модулей" в настройках менеджера модулей Joomla 4

После этого добавьте в адресной строке параметр &tp=1 и Вы увидите все модульные позиции Вашего шаблона. Чтобы вернуть всё обратно - уберите этот параметр из адресной строки. Если ничего не поменялось, то сначала установите параметр равным 0 - &tp=0, а потом уберите.

Проверка наличия модулей и их содержимого - countModules('position-name').

На практике таким простым шаблоном, как в примере выше, никто не пользуется. Часто вывод позиций содержит разного рода обёртки в вёрстке. Так, типовую 3-хколоночную сетку - правая, левая колонки и центральный основной текст - Вы задавать будете именно в index.php шаблона. Однако, если модули сайта на каких-то страницах не отображаются в данной позиции, то шорт-код <jdoc .../> ничего не выведет, а в HTML-коде останется лишняя разметка и мы увидим левую/правую колонку, но пустую. Дабы этого избежать в шаблон внедряется проверка на наличие модулей в данной позиции:

<?php if ($this->countModules('topbar')) : ?>
	<div class="container-fluid topbar">
		<jdoc:include type="modules" name="topbar"/>
	</div>
<?php endif; ?>

Метод $this->countModules('topbar') проверяет есть ли опубликованные модули в данной позиции и возвращает количество опубликованных модулей в позиции. В PHP при нестрогом сравнении int 0 будет логически равно false. Таким образом, если опубликованных модулей в позиции нет, то лишняя разметка выводиться не будет.

Но, бывают случаи, когда модуль опубликован на всех страницах. И на каких-то страницах ему есть что показать, а на каких-то нет. Такое поведение бывает у модулей фильтров товаров в каталогах, у модулей просмотренных товаров, когда ещё ни один товар не был просмотрен и т.д. Тогда получается, что модуль в позиции есть, в шаблоне будет показываться его обёртка из вёрстки, но контента в нём по факту нет. Для таких случаев в Joomla 4 внедрён второй параметр для метода countModules, который называется withContentOnly. Он принимает на вход true или false, по умолчанию - false. Если этот параметр равен true, то Joomla выполняет предварительный рендер модулей и смотрит присутствует ли результирующий HTML-вывод модулей - их контент. Если нет, то позиция выводиться не будет. Этот параметр нужно использовать там, где нужно. Например, шапка сайта - с логотипом, меню, контактами, кнопками "заказать звонок" на сайте присутствует всегда. Также и подвал сайта с логотипом, частью меню, контактами и другой полезной информацией - тоже присутствует всегда, на всех страницах сайта. Поэтому для этих позиций нет смысла делать пререндер модулей. В то время как для боковых колонок, позиций над и под выводом компонента и другими это может иметь смысл.

<?php 
// Параметр true выполнит пре-рендер содержимого модулей и если модуль есть, но 
// контента нет - данный блок разметки выводиться не будет.
if ($this->countModules('topbar', true)) : ?>
	<div class="container-fluid topbar">
		<jdoc:include type="modules" name="topbar"/>
	</div>
<?php endif; ?>

Чаще всего данный код используется для проверки и вывода модулей одной и той же позиции: проверяем есть ли модули в позиции topbar и если есть, то выводим их. Но здесь можно предположить и более сложные конструкции, когда мы проверяем наличие модулей и их содержимого в одной позиции и при этом выводим другой модуль. Например

<?php 
// Если есть модули и их содержимое в позиции topbar -
// выведем модули в позиции bottom-bar
if ($this->countModules('topbar', true)) : ?>
	<div class="container-fluid bottom-bar">
		<jdoc:include type="modules" name="bottom-bar"/>
	</div>
<?php endif; ?>

Показ позиций только на определённых страницах.

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

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

Настройки привязки модулей к пунктам меню в Joomla 4
Настройки привязки модулей к пунктам меню в Joomla 4

В этих случаях нам нужно работать с параметрами URL Joomla. Все URL в Joomla (после включения SEF) выглядят человеко-понятно (ЧПУ) - то есть site.ru/category-alias/article-name. Однако, "под капотом" нам доступны традиционные URL с GET-параметрами. И опираясь на их значения мы можем выстраивать логику показа позиций. Выключите SEF на своём Joomla-сайте, чтобы увидеть URL вида index.php?option=com_... и Вы увидите что-то вроде этого: index.php?option=com_content&view=article&id=2 для компонента материалов. Или index.php?option=com_jshopping&controller=product&task=view&category_id=3&product_id=2 для компонента интернет-магазина JoomShopping.

Параметр option равен системному имени компонента. com_content для материалов и категорий Joomla, com_contact для компонента контактов, com_jshopping для интернет-магазина JoomShopping, com_virtuemart для интернет-магазина Virtuemart и т.д. У любого компонента Joomla есть свой уникальный option-параметр в URL.

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

Чаще всего встречаются следующие параметры URL:

  • option - системное имя компонента

  • controller - может быть разным для категории и товара, например. controller=category, controller=product

  • view - вид. Может быть разным для категории и материала или контакта. view=category, view=article, view=contact.

  • layout - определяет параметры вида. Например layout=edit.

  • task - ещё один параметр, который может использоваться в компонентах Joomla.

Чтобы получить значения этих параметров в шаблоне используется метод getInput() объекта приложения Joomla:

<?php
use Joomla\CMS\Factory;

defined('_JEXEC') or die;

$app = Factory::getApplication(); 
// Получаем любые параметры из Input
// Это могут быть данные из $_GET или $_POST
// или из $_SERVER
$option     = $app->getInput()->getCmd('option', '');
$controller = $app->getInput()->getCmd('controller', '');
$view       = $app->getInput()->getCmd('view', '');
$layout     = $app->getInput()->getCmd('layout', '');
$task       = $app->getInput()->getCmd('task', '');
$itemid     = $app->getInput()->getCmd('Itemid', '');

В методе getCmd('parameter_name','default_value') parameter_name - имя параметра запроса (в том числе GET-запроса). default_value - значение по умолчанию, если запрашиваемый параметр отсутствует или будет пустым. Метод $app->getInput() возвращает объект Input, который раньше в Joomla 2.5 и Joomla 3.x назывался JInput. Официальная документация.

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

<?php 
use Joomla\CMS\Factory;

defined('_JEXEC') or die;

$app = Factory::getApplication(); 
// Получаем любые параметры из Input

$option     = $app->getInput()->getCmd('option', '');
$view       = $app->getInput()->getCmd('view', '');

// Если есть модули и их содержимое в позиции topbar выведем позицию
if ($this->countModules('topbar', true) && $option == 'com_content' && $view == 'category') : ?>
	<div class="container-fluid topbar-bar">
		<jdoc:include type="modules" name="topbar-bar"/>
	</div>
<?php endif; ?>

Проверять на $option лучше всегда, так как у Вас на сайте могут использоваться одновременно несколько компонентов, которые могут иметь в своём url параметр $view. И Ваши модули могут вылезти там, где не нужно. Ещё пример - выводим модульную позицию только в карточке товара компонента интернет-магазина JoomShopping.

<?php 
use Joomla\CMS\Factory;

defined('_JEXEC') or die;

$app = Factory::getApplication(); 
// Получаем любые параметры из Input

// тут будет 'com_jshopping'
$option     = $app->getInput()->getCmd('option', ''); 
// тут будет 'product'
$controller       = $app->getInput()->getCmd('product', '');
// тут будет 'view' (т.е. просмотр), а может быть 'edit' или что-то ещё
$task       = $app->getInput()->getCmd('task', '');

// Если есть модули и их содержимое в позиции topbar выведем позицию
if ($this->countModules('topbar', true) 
    && $option == 'com_jshopping' 
    && $controller == 'product' 
    && $task == 'view') : ?>
	<div class="container-fluid topbar-bar">
		<jdoc:include type="modules" name="topbar-bar"/>
	</div>
<?php endif; ?>

Логику отображения позиций можно использовать любую: по сочетанию условий, отрицанию условия и т.д. Документация PHP: операторы сравнения.

Не показывать вывод компонента на главной странице.

Ещё одна типовая задача, которую можно решить разными способами. Содержимое главной страницы зависит от типа сайта (контентный, новостник, интернет-магазин, каталог, визитка и т.д.). Главная страница обычно собирается из блоков, которые выводят разную информацию из разных компонентов, либо её вообще делают в духе посадочной (лендинга).

Вариант 1 - используется компонент-билдер страниц. Ничего менять не нужно.

Вариант 2 - собрать нужные блоки для главной страницы из модулей. Тогда вывод компонента может только мешать, так как Joomla должна знать к каком компоненту принадлежит тот или иной пункт меню. Второй вариант, в свою очередь, может иметь 2 пути решения задачи:

  • отключать вывод компонента на главной странице

  • использовать компонент "пустой страницы", главная задача которого... ничего не показывать.

Чтобы отключить вывод компонента на главной странице в Joomla нам пригодится класс для работы с Uri - Joomla\CMS\Uri\Uri.. В нём есть 2 метода, возвращающих текущий страницу и base uri. Мы сравниваем и если они не равны - можно выводить данные компонента. Почему не равны? Потому, что когда мы находимся на любой другой странице, кроме главной, метод Uri::current() будет возвращать нам url вида https://my-sute.ru/category-name, а метод Uri::base() - только https://my-sute.ru. Если же они оказываются одинаковыми, то это признак нахождения на главной странице.

<?php

use Joomla\CMS\Uri\Uri;

defined('_JEXEC') or die;

if(Uri::current() !== Uri::base()) :?>
<!-- Этот блок кода не будет показываться на главной странице сайта Joomla -->
  <main>
      <jdoc:include type="component"/>
  </main>
<?php endif; 

Способ уникализации страниц с помощью CSS и pageClass

В Joomla в настройках пунктов меню есть параметр CSS-класс страницы.

Вывод этого параметра зависит от конкретного шаблона. Но, в стандартном шаблоне Cassiopeia этот параметр назначается тегу <body> страницы.

<?php 
// Это фрагмент кода из файла index.php шаблона Cassiopeia

// Параметр CSS-класс страницы из настроек пункта меню
$pageclass = $menu !== null ? $menu->getParams()->get('pageclass_sfx', '') : '';

?>
<!-- И далее ниже по коду -->
<body class="site <?php echo $option
    . ' ' . $wrapper
    . ' view-' . $view
    . ($layout ? ' layout-' . $layout : ' no-layout')
    . ($task ? ' task-' . $task : ' no-task')
    . ($itemid ? ' itemid-' . $itemid : '')
    . ($pageclass ? ' ' . $pageclass : '')
    . $hasClass
    . ($this->direction == 'rtl' ? ' rtl' : '');
?>">

Поскольку CSS-класс будет назначен всей странице, это означает, что в своих CSS правилах мы можем переиначить полностью весь дизайн только опираясь на наличие или отсутствие этого CSS класса у <body>.

/* Просто цвет ссылки - синий */
a { color: var(--bs-blue); }

/* А здесь - <body class="dark"> - цвет ссылки красный*/
body.dark a { color: var(--bs-danger); }

Таким образом можно создавать уникальные дизайны для отдельных страниц сайта, создавать темы (тёмная / светлая / рыжая / и т.д.) и "включать" их просто указанием нужного класса в админке Joomla.

Нюанс: в выводе некоторых компонентов Joomla параметр $pageclass может выводиться не только у <body> (за это отвечает файл шаблона), но и в области вывода компонента. Так происходит, например, в материалах Joomla (com_content) при просмотре полного текста материала.

Поэтому при построении путей селекторов в CSS нужно быть внимательным. Либо сделать переопределение макета в шаблоне и убрать ненужный код.

Файл component.php

Если к любому url в Joomla добавить параметр tmpl=component, то в ответ Вы получите содержимое вывода только компонента, без окружающих его модулей (без меню, шапки, подвала, боковых колонок и т.д.). Это часто используют в случаях, если нужно показать что-то во всплывающем окне, например, текст политики обработки персональных данных в форме обратной связи. В таких случаях ссылка около чекбокса вызывает модальное окно, а в модальном окне находится <iframe>, в атрибуте src которого ссылка на материал с параметром tmpl=component. Тогда пользователи Вашего сайта смогут ознакомиться с текстом без перехода на другую страницу. HTML-макет такого вывода данных находится в файле component.php.

Его содержимое, как правило, очень простое

<?php

// содержимое файла templates/system/component.php

defined('_JEXEC') or die;

/** @var Joomla\CMS\Document\HtmlDocument $this */

// Styles
$this->getWebAssetManager()->registerAndUseStyle('template.system.general', 'media/system/css/system-site-general.css');

?>
<!DOCTYPE html>
<html lang="<?php echo $this->language; ?>" dir="<?php echo $this->direction; ?>">
<head>
    <jdoc:include type="head" />
</head>
<body class="contentpane">
    <jdoc:include type="message" />
    <jdoc:include type="component" />
</body>
</html>

Если в Вашем шаблоне отсутствует файл component.php, то используется стандартный файл templates/system/component.php.

Для Ваших собственных нужд Вы можете сделать разные шаблоны вывода и реализовывать в них свою специфичную логику. В url запроса тогда Вы будете указывать параметр tmpl=component2 и для вывода данных использоваться будет файл templates/ваш_шаблон/component2.php. Иногда такие запросы используют для получения данных по ajax, хотя отдавать готовый HTML по ajax - не самая лучшая практика.

Файл error.php

Этот файл отвечает за вывод страницы 404. Кроме ошибки 404, в Joomla 4 этот же файл отвечает за вывод сообщения об ошибке 403. Дополнительную информацию можно также подчерпнуть на новом портале документации Joomla.

Если в шаблоне нет файла error.php, то используется системный файл из templates/system/error.php. Вы можете скопировать в свой шаблон системный файл и перенести туда часть вёрстки из основного шаблона или оформить по-своему полностью.

Главное отличие Joomla 4 (и Joomla 5) от Joomla 3 это то, что на странице ошибки теперь можно отображать модули (всё-таки посмотрите ссылку на документацию чуть выше, там как раз про это тоже). Этого очень не хватало в предыдущих версиях Joomla и веб-мастера, выполняя задания СЕО-специалистов и интернет-маркетологов изголялись как могли. Вплоть до обработки 404 в htaccess (вроде ничего страшного), где сервер перенаправлял на сохранённую прямо из браузера HTML-страницу сайта (а вот это уже страшно...).

Теперь Вы можете спокойно повторить на странице 404 и шапку, и подвал сайта, и меню и почти всё, что угодно. Это очень круто.

Но, есть нюанс. Нюанс заключается в том, что страница 404 является объектом не Joomla\CMS\Document\HtmlDocument, а Joomla\CMS\Document\ErrorDocument. Это означает, что, например, некоторые плагины на этой странице работать не будут. И если Вы используете, например, плагин для замены шорт-кодов (для контактов, названия компании, логотипа, ссылок на соц.сети и т.д.), то на странице 404 будут отображаться именно шорт-коды, а не контакты. Будьте внимательны и осторожны ))

Обычно при создании своего шаблона страницу для отображения ошибок копируют из стандартного (Cassipeia для Joomla 4+) и изменяют уже её. в ней содержится типовое сообщение об ошибке в духе "Устаревшая закладка/избранное" , "Кэш поисковой системы ссылается на устаревшую страницу сайта" и т.д. На самом деле эти сообщения уже малополезны для пользователей и поэтому надписи заменяют на фотографию "Админ в ужасе". Но для админов полезным будет код ошибки, её подробное описание и callstack.

В стандартном шаблоне Cassiopeia участок кода, отвечающий за вывод этих данных вкылядит так:

<?php //оставлю это здесь, а то подсветка синтаксиса Хабра хромает :( ?>
<blockquote>
    <span class="badge bg-secondary"><?php echo $this->error->getCode(); ?></span> <?php echo htmlspecialchars($this->error->getMessage(), ENT_QUOTES, 'UTF-8'); ?>
</blockquote>
<?php if ($this->debug) : ?>
    <div>
        <?php echo $this->renderBacktrace(); ?>
        <?php // Check if there are more Exceptions and render their data as well ?>
        <?php if ($this->error->getPrevious()) : ?>
            <?php $loop = true; ?>
            <?php // Reference $this->_error here and in the loop as setError() assigns errors to this property and we need this for the backtrace to work correctly ?>
            <?php // Make the first assignment to setError() outside the loop so the loop does not skip Exceptions ?>
            <?php $this->setError($this->_error->getPrevious()); ?>
            <?php while ($loop === true) : ?>
                <p><strong><?php echo Text::_('JERROR_LAYOUT_PREVIOUS_ERROR'); ?></strong></p>
                <p><?php echo htmlspecialchars($this->_error->getMessage(), ENT_QUOTES, 'UTF-8'); ?></p>
                <?php echo $this->renderBacktrace(); ?>
                <?php $loop = $this->setError($this->_error->getPrevious()); ?>
            <?php endwhile; ?>
            <?php // Reset the main error object to the base error ?>
            <?php $this->setError($this->error); ?>
        <?php endif; ?>
    </div>
<?php endif; ?>

Обратите внимание, что стак вызовов показывается только в случае, если в общих настройках сайта включён параметр "отладка системы" if ($this->debug).

Файл fatal.php

Не встречал, чтобы этот файл фигурировал в шаблонах, но он есть в системном шаблоне - templates/system/fatal.php.

Согласно примечанию, этот файл используется для отображения ошибок только в самых критических ситуациях. И даже в нём у нас есть возможность сделать свой дизайн. для этого нужно создать файл fatal-error.custom.php и поместить его не в папке со своим шаблоном, а в папке templates/system.

Файл offilne.php

Этот файл отображает заглушку "сайт выключен и находится на техническом обслуживании". Выключить сайт можно в Система - Общие настройки - "Сайт выключен".

Если файла offline.php нет в шаблоне, то будет использоваться системный файл из templates/system/offline.php. Тип документа здесь Joomla\CMS\Document\HtmlDocument, поэтому и модули и контент-плагины здесь работают. Как правило, эта страница отображает текст из общих настроек сайта и картинку на фон (или у заголовка) из настроек шаблона. Здесь же можно поместить какой-нибудь счётчик обратного отсчета а-ля Coming soon.

Стандартная страница offline обычно показывает форму входа на сайт. На моей практике, если такой страницей и пользуются, то довольно редко. Форму входа в таких случаях убирают.

Вариант оформления offline страницы шаблона Joomla 4+
Вариант оформления offline страницы шаблона Joomla 4+

Файл joomla.asset.json шаблона Joomla

Этот файл описывает необходимые для работы шаблона веб ассеты. Ещё раз адресую читателя к статье Как правильно подключать JavaScript и CSS в Joomla 4. В ней подробно раскрывается концепция Web Asset в Joomla 4 и Joomla 5, даны примеры кода и паттерны применения. От себя добавлю следующее:

  • в шаблоне мы описываем те веб-ассеты, которые нужны для данного конкретного шаблона.

  • веб-ассеты для расширений (модулей, плагинов, макетов модулей и плагинов, переопределений компонентов), которые используются на сайте, я предпочитаю оформлять отдельными плагинами. Об этом статья Использование WebAssetsManager Joomla 4 и добавление собственных пресетов с помощью плагина. Такие ассеты легко обновлять (всякие скрипты каруселей, лайтбоксов, masonry и т.д.) и легко использовать от проекта к проекту. Установил плагин, включил и всё работает. Также перед созданием своего собственного веб-ассета стоит поискать, может кто-то уже оформил популярный скрипт карусели в веб-ассет и тогда можно использовать уже готовое решение.

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

  • Также очень часто используется метод registerAndUseStyle() и registerAndUseSript(), которые по синтаксису похожи на метод HTMLHelper::script() (ex. JHtml). Эти методы позволяют регистрировать и использовать ассеты на лету, но нужно помнить о том, в какой момент жизненного цикла приложения добавляется ассет и не пытаться использовать его раньше его добавления.

На примере стандартного шаблона Joomla - Cassiopeia - можно увидеть, что в отдельные веб ассеты выделены CSS общего характера (template.css), которые используются всегда. А веб-ассеты частных случаев (страница редактирования материала с загруженным редактором, страница offline, дополнительные стили для страниц сайта, доступных авторизованным пользователям) - выделены в отдельные веб-ассеты, которые подключаются только при необходимости.

Из своей практики приведу случай интернет-магазина на 3-х языках: одного шрифта для русского, английского и китайского языков не было. Дизайнеры подобрали похожие внешне шрифты, поэтому подключать разные ассеты пришлось в зависимости от текущего языка сайта.

<?php

// Фрагмент кода в index.php шаблона

use Joomla\CMS\Factory;

defined('_JEXEC') or die;

$app = Factory::getApplication();
// Получаем код языка вида ru-RU, en-GB
$lang_tag 	= $app->getLanguage()->getTag();
// добавляем к нему префикс, для удобства чтения и именования файлов
$lang_tag = '-'.$lang_tag; 
// Подключаем web asset
$wa->useStyle('template.webtolk.font.lang'.$lang_tag);

Фрагмент joomla.asset.json

{
  "$schema": "https://developer.joomla.org/schemas/json-schema/web_assets.json",
  "name": "webtolk",
  "version": "1.0.0",
  "description": "This file contains details of the assets used by webtolk site template for Joomla 4.",
  "license": "GPL-2.0-or-later",
  "assets": [
    {
      "name": "template.webtolk.offline",
      "description": "The css file to be used when the site is offline and offline.php is being used.",
      "type": "style",
      "uri": "offline.css"
    },
    {
      "name": "template.webtolk.font.lang-ru-RU",
      "type": "style",
      "uri": "font-lang-ru-RU.css"
    },
    {
      "name": "template.webtolk.font.lang-en-GB",
      "type": "style",
      "uri": "font-lang-en-GB.css"
    },
    {
      "name": "template.webtolk.font",
      "type": "style",
      "uri": "font-lang.css"
    }
  ]
}

В css-файлах для css-переменной уже присваивалась разный font-family. Данный пример из файла font-lang-ru-RU.css:

@font-face {
	font-family: "RockStar-regular";
	src: url("../fonts/RS-regular.otf");
	font-weight: normal;
	font-style: normal;
	font-display: swap;
}
:root {
	--bs-font-sans-serif: "RockStar-regular";
}

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

Дочерние шаблоны (дочерние темы) Joomla 4

В Joomla не принят термин "темы", однако я поместил его в заголовок для разработчиков, которые не имеют опыта работы с Joomla. Поскольку дочерние шаблоны - тема для отдельной большой статьи, я помещу сюда ссылку на отдельную большую статью: Joomla Community Magazine - Sweet child o' mine... A deep dive into Joomla Child Templates (статья на английском языке, официальный журнал международного Joomla-сообщества).

Кратко:

  • дочерние шаблоны - продолжение развития механизма переопределений в Joomla 4

  • дочерние шаблоны появились в Joomla 4.1

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

  • остальные файлы используются из родительского шаблона

  • в XML-манифесте дочернего шаблона должен быть быть элемент <inheritable>1</inheritable> (писал об этом выше)

  • создать дочерний шаблон можно в Система - Шаблоны сайта - [конкретный шаблон] - кнопка "создать дочерний шаблон"

  • Подробнее можно прочесть (и посмотреть видео) в статье Новое в Joomla 4.1

Видео о дочерних шаблонах (английский язык):

Сценарий применения дочерних шаблонов Joomla

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

Это задача разделения общего и частного. Обычно разработчики для себя создают некий шаблон-заготовку, который затем поддерживают: обновляют версии Bootstrap, UIkit или других использованных ассетов. В частном случае конкретного сайта всегда есть изменения, которые нужны только для конкретного сайта. Такие изменения лучше всего поместить в дочерний шаблон.

Шаблоны с опциями (добавить настройки для своего шаблона Joomla)

В Joomla под капотом очень удобный конструктор форм. Есть много стандартных типов полей Joomla (официальная документация), а если их не хватает - всегда можно создать свой тип поля и использовать его. Кроме полей типа текст. число, список, textarea есть удобное поле типа subform (документация). Это поле, содержащее в себе повторяемую форму из нескольких простых полей. Таким образом можно в админке быстро "накликать" список повторяемых сущностей с разными параметрами.

Какие опции следует выносить в настройки шаблона?

Если кратко, то те, которые имеют отношение ко всему шаблону. Это своего рода глобальные настройки внешнего вида Вашего сайта. Это могут быть настройки логотипа, шрифтов, цветовых схем, фавиконок, коды верификации поисковиков, соц.сетей, сервисов, возможность вставки кастомного кода из админки (после открывающего <body>, перед закрывающим </body> и т.д.).

Например, на всём сайте нужен логотип.

  • Его могут захардкодить прямо в index.php шаблона

  • Его могут вставить в модуль типа HTML-код

  • Можно сделать параметр шаблона и указывать картинку именно в нём.

Создание интерфейса настроек шаблона Joomla в XML-манифесте

В XML-манифесте шаблона есть секция <config>. В ней описываются поля для создания интерфейса в админке Joomla.

<?xml version="1.0" encoding="utf-8"?>
<extension type="template" client="site" method="upgrade">
<!-- тут мы пропускаем всё то, что писали раньше и переходим
сразу к нужной секции config -->
    <config>
        <fields name="params">
          <fieldset name="basic">
                <field
                        name="logo_file"
                        type="media"
                        types="images"
                        label="TPL_WEBTOLK_BRAND_IMG"
                        showon="brand:img_file"
                />
            </fieldset>
		</fields>
	</config>
</extension>

Почему такая структура в XML? Зачем <config>, затем <fields>, ещё и <fieldset> потом?

Элемент <config> - говорит, что это настройки шаблона.

Элемент <fields> влияет на рендер HTML-формы в админке. Их может быть несколько вложенных друг в друга. В примере мы видим <fields name="params">. Это означает, что все имена полей в настройках шаблона получат префикс jform[params]. А в базе данных есть колонка с именем params, куда сохраняется json с параметрами шаблона. Чудесным образом всё состыкуется :) Так, если имя поля для логотипа - logo_file, то в HTML-коде админки имя поля будет jform[params][logo_file], а в index.php Вашего шаблона будете получать данные этого поля следующим образом:

<?php
// Это файл index.php Вашего шаблона
// Здесь будет находиться путь к картинке вида images/my_picture.webp
echo $this->params->get('logo_file');

Если Вам нужна более сложная вложенность имён в структуре данных - внедряем в XML-формы ещё один <fields name="level2">. И все поля внутри <fields name="level2"> получат ещё один уровень вложенности по структуре данных.

<fields name="canvases">
  <fields name="front">
      <fieldset name="canvas_front">
          <field type="media"
                 name="canvas_image_front"
                 label="COM_WTPRODUCTBUILDER_PRODUCT_IMAGE_FRONT"
                 types="images"
                 preview="true"
                 parentclass="col-12 col-md-6 col-lg-4"/>
      </fieldset>
  </fields>
</fields>

Это пример не из шаблона, но суть он передаёт. Данные поля canvas_image_front будут доступны в виде:

<?php 
$canvases = $this->params->get('canvases');

А $canvases уже будет многомерным массивом с элементом front, в котором находится элемент canvas_image_front

Элемент <fieldset> формирует табы в панели администратора. Атрибут name должен быть уникальным. Атрибут label - это название таба. Атрибут description - отображаемое описание для вкладки.

Как Вы успели заметить в примерах XML полей есть любопытные атрибуты - showon и parentClass (class, кстати, тоже можно использовать).

Атрибут showon позволяет скрывать или показывать поле в админке в зависимости от значения другого поля (официальная документация). Удобная вещь, когда параметров много и не хочется работать со страницей админки современной CMS как с многосекционным однофайловым конфигом FIDONet-софта.

Атрибут parentClass позволяет задать css-класс родительскому элементу поля - это div-обёртка, в которой находится само поле и его label - название. Задать можно любой класс из шаблона админки Joomla (а это Bootstrap 5 + кастомные стили).

Например, parentClass="stack" поместит название поле над полем. Так экономится место на экране. Админка Joomla использует css grid на 6 колонок. Можно удобно группировать поля рядом: parentclass="stack span-3" - изменит размер поля, а parentclass="stack span-3-inline" позволит поместить поле рядом с другим полем. Подробнее смотрите css админки шаблона Joomla - media/templates/administrator/atum/css/template.css.

Большая часть настроек шаблона - это радиокнопки (выключатели), списки (списки файлов, шрифтов, CSS, простые текстовые поля или textarea.

Пример, как добавить коды верификации поисковиков, соц.сетей и сервисов в свой шаблон.

В XML-манифесте нужно добавить поле типа subform

<!-- В label должна быть языковая константа, но пишу сразу по-русски, 
чтоб было понятнее -->
<field name="verification_codes"
       label="Коды верификации"
       type="subform"
       layout="joomla.form.field.subform.repeatable-table"
       formsource="templates/webtolk/subform/search_consoles_meta.xml"
       multiple="true"
       buttons="add,remove"
/>

Поле этого типа загружает из файла повторяемую форму с собственно опциями. В index.php в $this->params->get('verification_codes') потом получим массив со значениями для рендера.

<?xml version="1.0" encoding="UTF-8"?>
<form>
	<fieldset name="search_engine_types">
		<field name="search_engine" type="list" label="Сервис для верификации">
			<option value="yandex-verification">Yandex</option>
			<option value="google-site-verification">Google</option>
			<option value="mailru-domain">Mail.ru</option>
			<option value="msvalidate.01">Bing</option>
			<option value="baidu-site-verification">Baidu</option>
			<option value="cmsmagazine">CMS Magazine</option>
			<option value="p:domain_verify">Pinterest</option>
		</field>
		<field name="search_engine_verification_code" type="text" label="Код верификации"/>
	</fieldset>
</form>

В настройках шаблона у нас появится сабформа для настроек с выпадающим списком поисковиков и сервисов и текстовым полем для кода верификации.

Далее, в index.php шаблона обрабатываем полученные из настроек данные и добавляем в <head> страницы.

<?php
// это фрагмент файла index.php Вашего шаблона
/**
 * Search engines webmaster's consoles verifictation codes
 */

// Проверяем, а есть ли вообще эти коды?
if ($this->params->get('verification_codes') && !empty($this->params->get('verification_codes')))
{
    // Проходим их все
	foreach ($this->params->get('verification_codes') as $search_engine)
	{
        // Проверяем, а не не забыли ли указать собственно код верификации?
		if (!empty($search_engine->search_engine_verification_code))
		{
          // Вроде всё на месте. Добавляем мета-тег
			$this->addCustomTag('<meta name="'.$search_engine->search_engine.'" content="'.$search_engine->search_engine_verification_code.'"/>');
		}
	}
}

У каждого Joomla-специалиста обычно кристаллизуется свой набор опций для шаблона, которые постепенно добавляются в разных проектах. При проектировании шаблона - повторю эту мысль - важно разумно распределить ресурсы между общим и частным. Надеюсь, данная статья поможет в этом.

Шаблоны и стили шаблона Joomla

Нередко для разных страниц сайта бывают необходимы вариации внешнего вида. В Joomla с давних пор существует функционал стилей шаблона.

Стили шаблона в Joomla

В разрабатываемом нами шаблоне теперь есть свои настройки: цветовые схемы, изображение логотипа, фавиконки, фиксированный или "резиновый" контейнер для сайта и т.д. Разные комбинации этих настроек можно сохранять в качестве своеобразных пресетов - "стилей" - и применять эти стили к определенным пунктам меню. Пунктам меню, в свою очередь, можно назначить отображение определенным группам пользователей, языкам сайта и т.д.

Этот функционал появился ещё линейке 2.5, если не раньше. Небольшое видео демонстрирует этот функционал на примере Joomla 3.9. (видео демо взято из более ранней статьи).

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

Но в таком случае нужно иметь в виду, что шаблон должен содержать параметры, которые нужно изменять от раздела к разделу сайта. В то время как коды верификации поисковых систем, js-коды аналитики вставить другими способами, поскольку они общие для всего сайта.

Сущности шаблонов и стилей в Joomla позволяют хоть для каждого пункта меню назначить полностью уникальный дизайн. Сделать это можно как абсолютно разными шаблонами (5 пунктов меню = 5 разных шаблонов

Источник: https://habr.com/ru/articles/760850/


Интересные статьи

Интересные статьи

Что такое react-контекст?React Context API - это интерфейс, который позволяет сохранять некоторую величину (переменную или объект), и использовать ее между несколькими компонентами. Под самим же конте...
Поскольку, худо ли - бедно, я добился удалённой отладки для надстроек (напомню, так почему-то  назвали разработчики «МойОфис» макросы с возможностью использовать пусть и примитивный, но набор кон...
Парадокс, конечно, но это возможно. Казалось бы, причем тут класс ядра для работы со строками url. Но именно он может помочь нам в Joomla 4. Статья о том, как автоматически определять размеры файлов и...
Довольно распространенная задача – создание превью картинок для сайта из полноразмерных изображений. Автоматизируем этот процесс с помощью триггера для Yandex Object Stor...
Привет, Хабр! Предлагаю вашему вниманию перевод статьи основателя сервиса Meetspaceapp Nick Gauthier «Building Minimal Docker Containers for Go Applications». Время чтения: 6 минут Существу...