Создание "правильного" шаблона для сайта
Для компактности HTML кода буду использовать библиотеку Bootstrap4 - пользуйтесь своими любимыми фреймворками, если не нравится. Итак, сделаем код нашего шаблона несколько более полным:
<?php $page = $variables['full:page']; ?> <!DOCTYPE html> <html> <head> <base href="/templates/default/"> <title><?= $page->title ?></title> <meta charset="utf-8"> <meta name="description" content="<?= $page->description ?>"> <meta name="keywords" content="<?= $page->keywords ?>"> <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css"> </head> <body> <header> </header> <main> <section> <div class="container"> <div class="row"> <div class="col-12"> <h1><?= $page->h1 ?></h1> </div> <div class="col-12"> <p><?= $page->content ?></p> </div> </div> </div> </section> </main> <footer> </footer> <script src="https://code.jquery.com/jquery-3.2.1.slim.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js"></script> <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js"></script> </body> </html>
Теперь главная страница сайта приобрела более "причёсанный" вид:
Заметим, что Title у страницы пустой, что не слишком хорошо. Можно прописывать это поле для каждой страницы. Но есть способ получше.
Настраиваем Title и другие SEO-параметры
В шаблоне меняем строки заголовка, описания и ключевых слов на:
<title><?= $this->escape($variables['title']) ?></title> <meta name="description" content="<?= $variables['meta']['description'] ?>"> <meta name="keywords" content="<?= $variables['meta']['keywords'] ?>">
и видим теперь заголовок <title>UMI.CMS - Страница 1</title>. Нам "UMI.CMS - " ни разу не нужно. Чтобы настроить параметры по умолчанию, в модулях (под бабочкой) находим раздел SEO, в нем справа вверху видим ссылку "Настройка модуля", жмём и настраиваем, там всё просто. Заменяю "UMI.CMS - " на "Демонстрационный сайт - ".
Чем отличается от прежнего варианта шаблона? Тем, что мы не выводим тупо поле из данных конкретной страницы, а позволяем CMS сформировать для нас эти параметры, используя настройки по умолчанию.
Делим шаблон на части
Чтобы не мучиться с длинной простынёй кода, существует хорошая практика делить его на разумные фрагменты. Скажем, сразу хочется выделить <head>, <header> и <footer>.
В директории /templates/default/php/ создаём поддиректорию layout, а в ней файлы наших фрагментов:
- head.phtml
- header.phtml
- main.phtml
- footer.phtml
Помещаем в эти файлы фрагменты кода шаблонов, например, head.phtml будет выглядеть вот так:
<head> <base href="/templates/default/"> <title><?= $variables['@title'] ?></title> <meta charset="utf-8"> <meta name="description" content="<?= $variables['meta']['description'] ?>"> <meta name="keywords" content="<?= $variables['meta']['keywords'] ?>"> <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css"> </head>
А main.phtml вот так:
<?php $page = $variables['full:page']; ?> <main> <section> <div class="container"> <div class="row"> <div class="col-12"> <h1><?= $page->h1 ?></h1> </div> <div class="col-12"> <p><?= $page->content ?></p> </div> </div> </div> </section> </main>
Теперь в шаблоне можно просто подключить эти фрагменты:
<!DOCTYPE html> <html> <?= $this->render($variables, 'layout/head') ?> <body> <?= $this->render($variables, 'layout/header') ?> <?= $this->render($variables, 'layout/main') ?> <?= $this->render($variables, 'layout/footer') ?> <script src="https://code.jquery.com/jquery-3.2.1.slim.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js"></script> <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js"></script> </body> </html>
Заметим, что в качестве первого параметра при вызове метода render() мы передаем массив $variables конкретной страницы. Второй параметр - это адрес шаблона относительно папки php и без расшмрения ".phtml". Поэтому делать у файлов шаблона именно такое расширение - обязательно! Иначе не найдет.
Добавляем меню
Выше мы использовали волшебную переменную $this, но для вызова только одного метода - render(). А какие еще методы нам доступны?
Полный список был бы весьма желателен. Но если кратко - все публичные методы модуля content, их описание и код можно посмотреть в /classes/components/content/class.php и /classes/components/content/macros.php, а также системные и сервисные методы, наследуемые этими классами. Методы класса можно использовать непосредственно, макросы - при помощи метода macros().
Нам для сайта надо получить "дерево" меню. Для этого в файл header.phtml добавляем код:
<?php $pageId = isset($variables['@pageId'])?$variables['@pageId']:0; $menuTree = $this->macros('content', 'menu', [0, 2, 0, true, $pageId]); var_dump($menuTree); ?> <header> </header>
Первый параметр метода macros() - название модуля, второй - название метода, третий - параметры, передаваемые методу. Список параметров можно посмотреть в коде метода, все макросы хорошо документированы комментариями. В данном случае используем:
- шаблон не задан (шаблон задается в других шаблонизаторах, в PHP не работает)
- 2 уровня вложенности (у нас пока один, но можем потом добавить)
- начиная от корня сайта (можно указать id страницы, и тогда "дерево" будет построено от неё)
- выдавать признак, что есть дочерние страницы
- id текущей страницы передаем, чтобы в результате этот пункт был выделен как активный.
Чтобы изучить возможность добавления второго уровня, добавим вложенную страницу внутрь нашей "Страницы 1". Для этого с разделе "Структура" сайта ставим галочку рядом со "Страница 1" и нажимаем плюс в меню. Назовем ее "Страница 3" и page3 в качестве псевдостатического адреса. Обновляем страницу в браузере - в массиве $menuTree ничего не поменялось!!!
Это очередная засада UMI CMS. Чтобы используемый нами макрос выдавал вложенные страницы, надо в данном случае на "Странице 1" в Дополнительных параметрах поставить признаки "Меню всегда развернуто" и "Показывать подменю". Понятно, что это вопрос умолчаний, но в современных сайтах чаще используется развернутое меню, управляемое JS, а не как раньше - статическое индивидуальное меню для каждой страницы.
Господа разработчики, может, пора уже облегчить жизнь редакторам сайтов, и изменить настройки? Пусть у всех страниц эти признаки будут по умолчанию включены, как вы считаете?
Полюбовавшись структурой полученного массива, можем теперь вывести нормальное меню сайта:
<?php $pageId = isset($variables['@pageId'])?$variables['@pageId']:0; $menuTree = $this->macros('content', 'menu', [0, 2, 0, true, $pageId]); ?> <header> <nav class="navbar navbar-expand-lg navbar-light bg-light"> <a class="navbar-brand" href="#">Логотип</a> <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation"> <span class="navbar-toggler-icon"></span> </button> <div class="collapse navbar-collapse" id="navbarSupportedContent"> <ul class="navbar-nav mr-auto"> <?php foreach ($menuTree['void:lines'] as $item) { $dropdown = !empty($item['items']['nodes:item']); $active = !empty($item['attribute:status']); if (isset($item['@link']) && isset($item['@name'])) { if ($dropdown) { ?> <li class="nav-item dropdown <?=$active?'active':''?>"> <a class="nav-link dropdown-toggle" href="<?= $item['@link'] ?>" id="navbarDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"><?= $item['@name'] ?></a> <div class="dropdown-menu" aria-labelledby="navbarDropdown"> <?php foreach ($item['items']['nodes:item'] as $sub) { if (isset($sub['@link']) && isset($sub['@name'])) { ?> <a class="dropdown-item" href="<?= $sub['@link'] ?>"><?= $sub['@name'] ?></a> <?php } } ?> </div> </li> <?php } else { ?> <li class="nav-item <?=$active?'active':''?>"> <a class="nav-link" href="<?= $item['@link'] ?>"><?= $item['@name'] ?></a> </li> <?php } } } ?> </ul> </div> </nav> </header>