Создание файловых шаблонов pdoTools

Создание файловых шаблонов pdoTools MODX Revo

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

Приблизительный будущий дизайн

Простой и как по мне довольно симпатичный — сделаем что-то подобное.

Создаем базовый шаблон

Базовый шаблон — это шаблон который включает в себя все сквозные элементы верстки, обычно это шапка и футер.

Все файловые шаблон должны быть с разрешением .tpl, следовательно назовем его base.tpl. Создаем в директории template/tpl/templates, если подключились по FTP через VS Code или админку, как я описывал в предыдущем уроке, то директория в нем должна быть следующей tpl/templates — там уже создаем файл base.tpl.

Создание файла

В него копируем код из шаблона BaseTemplate — который находится в админке.

Код базового шаблона

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

Удаляем из кода по очереди все чанки: {include ‘header’}, ({include ‘footer’} и т.д. и место них вставляем код из этих чанков. В конечном итоге получаем такой код шаблона base.tpl:

<!DOCTYPE html>
<html lang="{$.en ? 'en-US' : 'ru-RU'}">
<head>
{set $title = ($_modx->resource.longtitle ?: $_modx->resource.pagetitle) | notags}
{set $description = $_modx->resource.description | replace :' "':' «' | replace :'"':'»'}
{set $page = 'site_url' | config ~ $_modx->resource.uri}

<meta charset="utf-8">
<meta http-equiv="x-ua-compatible" content="ie=edge">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1,shrink-to-fit=no">

<title>{$title} | {'site_name' | config}</title>
<meta name="description" content="{$description}">
<meta name="keywords" content="{'seoPro.keywords' | placeholder}">
<meta name="robots" content="{'seoTab.robotsTag' | placeholder}">

<meta name="csrf-token" content="{$.session['csrf-token']}">

{'!hreflang' | snippet}

<!-- https://realfavicongenerator.net/ -->
{*<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png">
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png">
<link rel="manifest" href="/site.webmanifest">
<link rel="mask-icon" href="/safari-pinned-tab.svg" color="#5bbad5">
<meta name="msapplication-TileColor" content="#da532c">
<meta name="theme-color" content="#ffffff">*}

<!-- Facebook Open Graph -->
<meta property="og:url" content="{$page}">
<meta property="og:type" content="website">
<meta property="og:title" content="{$title}">
<meta property="og:image" content="">
<meta property="og:description" content="{$description}">
<meta property="og:site_name" content="{'site_name' | config}">

<!-- Twitter Card -->
<meta name="twitter:card" content="summary">
<meta name="twitter:site" content="@site_account">
<meta name="twitter:creator" content="@individual_account">
<meta name="twitter:url" content="{$page}">
<meta name="twitter:title" content="{$title}">
<meta name="twitter:description" content="{$description}">
<meta name="twitter:image" content="">

<!-- Schema.org -->
<meta itemprop="name" content="{$title}">
<meta itemprop="description" content="{$description}">
<meta itemprop="image" content="">

<!-- dns-prefetch -->
<link href='//fonts.googleapis.com' rel='dns-prefetch'>
<link href='//ajax.googleapis.com' rel='dns-prefetch'>
<link href='//cdn.jsdelivr.net' rel='dns-prefetch'>
<link href='//cdn.polyfill.io' rel='dns-prefetch'>
<link href='//cdnjs.cloudflare.com' rel='dns-prefetch'>
<link href='//unpkg.com/' rel='dns-prefetch'>

<!-- preconnect -->
<link href="https://fonts.gstatic.com" rel="preconnect" crossorigin>

<script type="application/ld+json">
{
   "@context": "http://schema.org",
   "@type": "Organization",
   "url": "{$page}",
   "logo": "{'logo' | config}"
}
</script>

{'!breadSchema' | snippet}

<base href="{'site_url' | config}" />
    {block 'minifyx'}
        {'!MinifyX' | snippet : [
            'minifyCss' => 1,
            'minifyJs' => 1,
            'registerCss' => 'default',
            'registerJs' => 'startup',
            'preHooks' => 'loading.php,libs.php',
            'hooks' => '',
            'cssTpl' => 'boilerplate_tpl_css' | config,
            'jsTpl' => 'boilerplate_tpl_js' | config,
            'libsCss' => 'bootstrapCss,ajaxFormCss,magnificCss,sweetAlertCss',
            'libsJs' => 'jqueryJsCDN,ajaxFormJs,ajaxFormJsInit--inline,lazySizesJs,magnificJs,sweetAlertJs',
            'cssGroups' => '',
            'jsGroups' => '',
            'cssSources' => '',
            'jsSources'  => ''
        ]}
    {/block}
</head>
<body class="{block 'classesBody'}body loading page-{$_modx->resource.id} parent-{$_modx->resource.parent}{/block}">
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
    <div class="container">
        <a class="navbar-brand" href="/" title="{'site_name' | config}">{'site_name' | config}</a>
        <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbar"
                aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
            <span class="navbar-toggler-icon"></span>
        </button>
        <div class="collapse navbar-collapse" id="navbar">
            <ul class="navbar-nav mr-auto">
                {'!pdoMenu' | snippet: [
                    'parents' => '0',
                    'resources' => '',
                    'displayStart' => 1,
                    'level' => 2,
                    'limit' => 0,
                    'tplOuter' => '@INLINE {$wrapper}',
                    'tpl' => '@INLINE <li class="nav-item {$classnames}">
                                <a class="nav-link" href="{$link}" title="{$menutitle}" {$attributes}>{$menutitle}</a>
                            </li>',
                    'tplParentRow' => '@INLINE <li class="nav-item dropdown {$classnames}">
                                        <a href="#" class="nav-link dropdown-toggle" data-toggle="dropdown" title="{$menutitle}" {$attributes}>{$menutitle}</a>
                                        <ul class="dropdown-menu" aria-labelledby="navbarDropdown">{$wrapper}</ul>
                                    </li>',
                    'tplInnerRow' => '@INLINE <a class="dropdown-item" href="{$link}" title="{$menutitle}" {$attributes}>{$menutitle}</a>'                
                ]}
            </ul>
        </div>
    </div>
</nav>
{block 'content'}

{/block}
<footer class="footer bg-dark text-white">
    <div class="footer-copyright text-center py-3">© {'' | date: 'Y'} Copyright:
        <a href="{'site_url' | config}" title="{'site_name' | config}">{'site_name' | config}</a>
    </div>
</footer>
{if $_modx->user.id == 1}
<script>
    function Info(totalTime, queries, memory, source) {
        this['Время запросов:'] = totalTime;
        this['Количество запросов:'] = queries;
        this['Используемая память:'] = memory;
        this['Источник:'] = source;
    }
    {set $info = $_modx->getInfo('', false)}
    var info = new Info( '{$info.totalTime}', '{$info.queries}', '[^m^]', '{$info.source}' );
    console.table(info);
</script>
{/if}
</body>
</html>

Т.е. сюда мы вынесли сквозные блоки (верстку допилим в конце урока), а в конструкцию:

{block 'content'} {/block}

будут подключаться шаблоны для страниц.

Немного о верстке, разбор и допил базового шаблона

Начнем мини разбор сверху вниз.

<html lang="{$.en ? 'en-US' : 'ru-RU'}"> и {'!hreflang' | snippet}

Boilerplate создает плагин переключения контекстов, т.к. сайт у нас будет на 1 языке можно смело избавляться от вызова сниппета hreflang и тег html сделать таким: <html lang="ru-RU">

Далее от всего, что связано с мета тегами и разметками можно избавиться, т.к. за это все будет отвечать пакет SEO Suite.

Закомментированный кусок с иконками тоже можно удалить.

Если вам не нужна техническая информация (можно посмотреть в исходном коде страницы):

Техническая информация

то можно смело удалять из шаблона следующую конструкцию:

{if $_modx->user.id == 1}
<script>
    function Info(totalTime, queries, memory, source) {
        this['Время запросов:'] = totalTime;
        this['Количество запросов:'] = queries;
        this['Используемая память:'] = memory;
        this['Источник:'] = source;
    }
    {set $info = $_modx->getInfo('', false)}
    var info = new Info( '{$info.totalTime}', '{$info.queries}', '[^m^]', '{$info.source}' );
    console.table(info);
</script>
{/if}

Обновление библиотек до актуальных версий

На текущий момент подключает Boilerplate подключает немного устаревшие библиотеки скриптов например: bootstrap 4.3.1 и их желательно обновить библиотеки.

За подключение библиотек отвечает вот эта конструкция:

{block 'minifyx'}
        {'!MinifyX' | snippet : [
            'minifyCss' => 1,
            'minifyJs' => 1,
            'registerCss' => 'default',
            'registerJs' => 'startup',
            'preHooks' => 'loading.php,libs.php',
            'hooks' => '',
            'cssTpl' => 'boilerplate_tpl_css' | config,
            'jsTpl' => 'boilerplate_tpl_js' | config,
            'libsCss' => 'bootstrapCss,ajaxFormCss,magnificCss,sweetAlertCss',
            'libsJs' => 'jqueryJsCDN,ajaxFormJs,ajaxFormJsInit--inline,lazySizesJs,magnificJs,sweetAlertJs',
            'cssGroups' => '',
            'jsGroups' => '',
            'cssSources' => '',
            'jsSources'  => ''
        ]}
    {/block}

Тут все довольно хитро сделано, хуки для MinifyX и т.д. В общем все подключаемые библиотеки лежат по адресу «assets/libs» следовательно мы их можем обновить, давайте разберем как на примере обновления Фреймворка bootstrap, обновим его до 4.6 (остальные библиотеки обновляться также).

Скачиваем актуальную версию bootstrap 4 (на данный момент это 4.6, да есть и бутстрап 5 о нем будет ниже). Распакуйте скачанный архив и закиньте из него файлы bootstrap.min.css и bootstrap.min.js (файлы bootstrap.min.css.map и bootstrap.min.js.map тоже нужно закинуть — особенно если править файлы bootstrap не собираетесь) с в паку «assets/libs/bootstrap». Далее нужно зайти в файл «core/components/minifyx/config/groups.php» и изменить строки:

// BOOTSTRAP
    'bootstrapCss' => [
        '/assets/libs/bootstrap/bootstrap.4.3.1.min.css'
    ],
    'bootstrapJs' => [
        '/assets/libs/bootstrap/bootstrap.4.3.1.min.js'
    ],
    'bootstrapCssCDN' => [
        '//stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css'
    ],
    'bootstrapJsCDN' => [
        '//stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js'
    ],

на

// BOOTSTRAP
    'bootstrapCss' => [
        '/assets/libs/bootstrap/bootstrap.min.css'
    ],
    'bootstrapJs' => [
        '/assets/libs/bootstrap/bootstrap.min.js'
    ],
    'bootstrapCssCDN' => [
        '//cdn.jsdelivr.net/npm/bootstrap@4.6.0/dist/css/bootstrap.min.css'
    ],
    'bootstrapJsCDN' => [
        '//cdn.jsdelivr.net/npm/bootstrap@4.6.0/dist/js/bootstrap.min.js'
    ],

Да за подключение библиотек отвечают параметры libsCss и libsJs в вызове MinifyX.

Переход на Bootstrap 5

В этом проекте мне не нужна библиотека jquery — либо если даже понадобиться, то не на многих страницах. Следовательно можно перейти на bootstrap 5 (он на обычном JS — не требует подключения jquery, но и в то же время можно его подключить, при необходимости). Поэтому чтобы не тащить лишнего и чтобы сайт был быстрее переведем его на 5 бутстрап, а если понадобиться мы его подключим по мере необходимости. Поэтому пока можно избавиться от вызова MinifyX.

Каким компонентам или сниппетам MODX нужен jquery?

AjaxForm — если у вас 1 форма на странице контактов (как в данном случае, то лучше сделать на Formit, либо подключить jquery на этой странице).

pdoPage — если нужна Аякс пагинация;

Tickets — если решите на нем к примеру комментарии в блоге сделать.

miniShop2 — если нужен магазин (корзина товаров, кнопка купить), мы делаем каталог — вообще отключим его библиотеки).

В общем это не все компоненты зависимые от jquery, еще раз повторюсь его можно будет подключить при необходимости, так что переходим на 5 бутстрап!

Базовый шаблон на bootstrap 5 без лишнего кода

В общем код финальной версии base.tpl с небольшой доработкой верстки:

<!DOCTYPE html>
<html lang="ru-RU">
<head>
<meta charset="utf-8">
<base href="{'site_url' | config}" />
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="csrf-token" content="{$.session['csrf-token']}">
<!-- dns-prefetch -->
<link href='//fonts.googleapis.com' rel='dns-prefetch'>
<link href='//ajax.googleapis.com' rel='dns-prefetch'>
<link href='//cdn.jsdelivr.net' rel='dns-prefetch'>
<link href='//cdn.polyfill.io' rel='dns-prefetch'>
<link href='//cdnjs.cloudflare.com' rel='dns-prefetch'>
<link href='//unpkg.com/' rel='dns-prefetch'>
<link href='//cdn.jsdelivr.net' rel='dns-prefetch'>
<!-- preconnect -->
<link href="https://fonts.gstatic.com" rel="preconnect" crossorigin>
<script type="application/ld+json">
{
   "@context": "http://schema.org",
   "@type": "Organization",
   "url": "{'site_url' | config}",
   "logo": "{'logo' | config}"
}
</script>
{'!breadSchema' | snippet}
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
</head>
<body class="{block 'classesBody'}body page-{$_modx->resource.id} parent-{$_modx->resource.parent}{/block}">
<nav class="navbar navbar-expand-lg navbar-light bg-white border-bottom">
  <div class="container">
    <a class="navbar-brand" href="/" title="{'site_name' | config}">{'site_name' | config}</a>
    <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-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 me-auto mb-2 mb-lg-0" itemtype="http://schema.org/SiteNavigationElement" itemscope="itemscope">
        {'!pdoMenu' | snippet : [
            'level' => 2,
            'parents' => 0,
            'firstClass' => '0',
            'lastClass' => '0',
            'rowClass' => 'nav-item',
            'tpl' => '@INLINE <li itemprop="name"{$classes}><a class="nav-link" itemprop="url" href="{$link}"{$attributes}>{$menutitle}</a>{$wrapper}</li>',
            'parentClass' => 'dropdown',
            'tplOuter' => '@INLINE {$wrapper}',
            'tplInner' => '@INLINE <ul class="dropdown-menu" aria-labelledby="navbarDropdown">{$wrapper}</ul>',
          'tplInnerRow' => '@INLINE <li><a itemprop="url" class="dropdown-item" href="{$link}"{$attributes}>{$menutitle}</a></li>{$wrapper}',
            'tplParentRow' => '@INLINE <li{$classes}><a itemprop="url" class="nav-link dropdown-toggle" href="{$link}"  id="navbarDropdown" role="button" data-bs-toggle="dropdown" aria-expanded="false"{$attributes}>{$menutitle}</a>{$wrapper}</li>'
        ]}
      </ul>
    </div>
  </div>
</nav>

{block 'content'}

{/block}
<footer class="border-top">
    <div class="container py-3">
        <a class="h4 text-dark" href="/" title="{'site_name' | config}">{'site_name' | config}</a>
    </div>
    <div class="footer-body bg-light">
        <div class="container py-3">
            <p>здесь будут какие-нибудь менюшки и т.д.</p>
        </div>
    </div>
    <div class="container text-center py-3">
        © {'' | date: 'Y'} Copyright: <a class="text-dark" href="{'site_url' | config}" title="{'site_name' | config}">{'site_name' | config}</a>
    </div>
</footer>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.min.js" integrity="sha384-QJHtvGhmr9XOIpI6YVutG+2QOK9T+ZnN4kzFN1RtK3zEFEIsxhlmWl5/YESvpZ13" crossorigin="anonymous"></script>
</body>
</html>

Здесь мы изменили вывод меню переписали его с bootstrap v4 под v5 (светлую тему) и добавить разметку shema.org + немного доработал футер. Для информации: про то как создавать меню, можно почитать урок: pdoMenu — документация и примеры создания меню в MODX.

Создание шаблона для главной страницы

В этой же директории (tpl/templates) создаем файл HomeTemplate.tpl пока со следующим содержимым:

{extends 'file:templates/base.tpl'}
{block 'content'}
<div class="bg-light">

<section class="py-4 bg-white">
    <div class="container">
        <div class="row">
            <div class="col-md-7 col-lg-8">
                <h1 class="mt-5 mb-4">{$_modx->resource.pagetitle}</h1>
                {$_modx->resource.introtext}
            </div>
            <div class="col-md-5 col-lg-4 d-none d-md-block">
                <img src="{$_modx->resource.img}" alt="{$_modx->resource.pagetitle}" class="img-fluid">
            </div>
        </div>
    </div>
</section>

<section class="py-4">
    <div class="container text-center">
        <h2>Популярные микрозаймы</h2>
        Здесь будет выборка из minishop2
    </div>
</section>

<div class="container card mb-3">
    <div class="card-body">
        {$_modx->resource.content}
    </div>
</div>

<section class="py-3">
    <div class="container text-center">
        <h2>Полезно почитать</h2>
        Здесь будет выборка статей
    </div>
</section>

</div>
{/block}

Здесь подключаем наш базовый шаблон base.tpl и в него помещаем все что находиться между {block 'content'} ... {/block}

Так же в данном шаблоне есть вывод TV поля img — тип ввода: изображение. Его вам нужно создать самостоятельно.

Теперь подключим шаблон главной страницы в админке. Идем в админку открываем шаблон BaseTemplate, удаляем весь старый код и в место него подключаем наш шаблон:

{include 'file:templates/HomeTemplate.tpl'}

Подключаем главный шаблон

Давайте сразу переименуем «BaseTemplate» в «Главная», поставим значок «icon-home» и сохраним.

Переименовывам шаблон, добавляем иконку и сохраняем

Тестирование работы главного шаблона

Открываем ресурс главная страница и заполняем какими-нибудь данными (можете взять с конкурента), заполнить желательно все (в том числе SEO поля — которые создает SEO SITE) — в следующем уроке мы их будем выводить. Сохраняем и смотрим.

Пример заполнения главной страницы

Для удобства я к introtext (Аннотация) подключил визуальный редактор.

Если все сделали правильно, то увидите примерно следующее.

Вид заполненной главной страницы

Создание шаблона для статических страниц

Статические страницы, это такие как: о проекте, о компании, контакты, политика конфиденциальности и т.д.

Создаем в директории tpl/templates файл StaticTemplate.tpl со следующим содержимым:

{extends 'file:templates/base.tpl'} 
{block 'content'} 
<header class="bg-light py-2 border-bottom">
    <div class="container"><h1>{$_modx->resource.pagetitle}</h1></div>
</header> 
<section class="bg-white py-4">
    <div class="container">{$_modx->resource.content}</div>
</section>
{/block}

В дереве «Элементы», в админке MODX, во вкладке шаблоны, открываем шаблон «Service» переименовываем его в «Статика», удаляем весь код и вместо него вставляем вызов нашего статического шаблона: {include 'file:templates/StaticTemplate.tpl'} и сохраняем.

Создание шаблона для статических страниц

Тестирование работы шаблона «Статика»

Создадим какой-нибудь ресурс например «О проекте» заполним его, применим шаблон «Статика» сохраним и посмотрим как это все выглядит.

Пример заполненной статической страницы

Пока у нас совсем пустой сайт особо нет смысла заниматься его внешним оформлением, тем более скоро сделаем конструктор блоков. В следующем уроке разберемся с компонентом SEO SITE — настроим его и выведем все в код

В следующем уроке будем немного дорабатывать наш базовый шаблон по SEO при помощи SEO Suite.

Примечание + ДЗ для тех кто незнаком с bootstrap

Можно обойтись одним универсальным базовым шаблоном под все — если сделать редактор блоков (довольно долгое занятие его сделать + не у всех получится) и получается конструировать разные типы страниц с разными блоками и контентом.

Т.к. все верстка будет строиться на фреймворке bootstrap 5 версии, ознакомьтесь с его документацией (классы, готовые блоки и т.д.).

Поделиться с друзьями
Алексей

Веб-дизайнер и SEO оптимизатор. Занимаюсь созданием сайтов с 2010 года и их продвижение с 2012 года!

Оцените автора
( 1 оценка, среднее 5 из 5 )
Web-Revenue.ru
Добавить комментарий