Перенос готовой верстки (шаблона)
Каждый html шаблон состоит из определенного набора файлов, обычно это html, css, js файлы и изображения. Также могут быть шрифты, scss файлы, php обработчики и т.д.
Скачать шаблон который используется в данном уроке, можно здесь: Шаблоны для MODX.
Для интеграции дизайна нам обычно нужно перенести на хостинг все файлы кроме html и php. В данном случае все, что нам нужно лежит в папке assets:
Создадим в корне сайта директорию templates
и закачаем все файлы из папки assets
туда. Сделать это можно при помощи файлового менеджера хостинга или через ftp/sftp. В конечном итоге получаем следующее:
Примечание! Можно не выносить файлы шаблона в отдельную папку, например можно залить всю папку assets в корень, тогда в дальнейшем не придется менять пути.
Теперь можно отредактировать базовый шаблон, для этого в дереве ресурсов перейдите во вкладку «Элементы» — «Шаблоны» и отредактируем «Начальный шаблон».
Как вы видите в начальном шаблоне присутствует синтаксис MODX: [[*name]]
— поля ресурсов и TV, [[++name]]
— системные настройки. Мы все это будем изучать его по мере разработки сайта, а сейчас можете удалить весь код шаблона.
Чтобы код MODX шаблонов подсвечивался установите дополнение Ace.
Теперь откройте код главной страницы html шаблона — обычно это файл index.html (делать это лучше при помощи редакторов кода) скопируйте и вставьте его в место стандартного кода начального шаблона.
И так как мы загрузили шаблон в свою папку templates, нам нужно поменять пути к css, js и прочим файлам. Пример: было assets/vendor/animate.css/animate.min.css, стало templates/vendor/animate.css/animate.min.css.
В нашем случае нам нужно везде assets заменить на templates. Если вы устанавливали дополнение Ace, то выделите assets, нажмите CTRL + H, в поле замены напишите templates и напротив заменить нажмите на все.
Иногда чтобы произошла замена, нужно щелкнуть по одной из стрелок в окне поиска и замены а потом уже жать на все.
После замены путей сохраните шаблон и откройте главную страницу, она должна стать такой же как у шаблона.
Если у вас весь код кривой, значит вы что-то не закачали, либо поправили не все пути до файлов.
Интеграция html верстки с CMS
Интеграция html верстки с CMS — это процесс объединения дизайна и верстки сайта (html, CSS, JavaScript) с системой управления контентом (CMS), в нашем случае с MODX. Это позволяет управлять контентом сайта через интерфейс CMS, без необходимости вручную изменять код сайта.
Иными словами нам нужно превратить статический код в динамический, чтобы значительно упростить процесс управления контентом и обновления сайта, а также при необходимости создавать более сложные и функциональные сайты.
Интеграция верстки в MODX часто начинается с определения того, какие элементы сайта обычно повторяются от страницы к странице. Если открыть все наши html файлы шаблоны и посмотреть на них, то вы увидите что у всех есть повторяющиеся элементы: шапка с навигацией (header), хлебные крошки (на всех страницах кроме главной), футер.
Это все так сказать сквозные элементы, их можно вынести в отдельные чанки.
Использование чанков
Чанки способ предложить управления повторяющимся контентом в одном месте. В приведенном выше примере шаблона есть статическая навигация в верхнем и нижнем колонтитулах, это может стать проблемой, если возникла необходимость изменить текст для одной из этих ссылок. Вместо изменения текста в каждом шаблоне и десинхронизации риска было бы предпочтительно обновить его один раз, и это изменение отразится на всех шаблонах. Мы можем сделать это, используя чанки.
Сделаем хитрую систему чанков: создаем чанк tpl и переносим в него весь код из начального шаблона, вместо него выводим созданный чанк.
Далее открываем чанк tpl.1, находим в нем разметку карусели: Hero Section (которая выводится только на главной странице). Вырезаем ее и помещаем в новый чанк с именем: hero_section.
и соответственно вызываем его: [[$hero_section]]. Далее вырезаем из чанка tpl весь контент (не сквозные элементы, которые находятся в main) и помещаем их в чанк tpl.1 и вызываем его. На выходе должно получится следующее:
Если сейчас открыть главную страницу, она не должна поменяться (должна остаться точно такой же как до использования чанков).
Использование стандартных полей ресурса
Открываем чанк со сквозными элементами и прописываем поля ресурсов. Например меняем:
<title>Eterna Bootstrap Template - Index</title>
<meta content="" name="description">
на
<title>[[*longtitle]]</title>
<meta content="[[*description]]" name="description">
Ну и вызовем где ни будь в tpl.1 поле [[*content]]
.
Недостаточно стандартных полей, можете создать свои TV.
Использование системных настроек
Вызовем самые ходовые системные настройки:
[[++site_url]]
— базовый урл (см. настройка чпу)
[[++modx_charset]]
— кодировка сайта
[[++site_name]]
— название сайта
[[++cultureKey]]
— язык сайта
Наше начало шаблона станет таким:
<!DOCTYPE html>
<html lang="[[++cultureKey]]">
<head>
<base href="[[++site_url]]">
<meta charset="[[++modx_charset]]">
<meta content="width=device-width, initial-scale=1.0" name="viewport">
<title>[[*longtitle]] | [[++site_name]]</title>
Так же мы можем создать свои системные настройки, сделать это проще всего при помощи дополнения ClientConfig, установите его и создайте там настройки: телефон, email, адрес, соц. сети и т.д.
Затем выведите их в нужных частях шаблона.
Использование фильтров и модификаторов
Усложним логику вывода чанков и стандартных полей, системных настроек при помощи фильтров и модификаторов.
Немного усложним вывод title
, сделаем его таким:
title
Добавим meta robots:
<meta name="robots" content="[[*searchable:is=`1`:then=`index, follow`:else=`noindex, nofollow`]]">
Модифицируем вызов чанков hero_section
и tpl.1
.
[[*id:is=`1`:then=`[[$hero_section]]`]]
Здесь мы выводим данный чанк только у ресурса с id = 1 (главной страницы).
[[$tpl.[[*template]]]]
А в данном случае мы в зависимости от шаблона подключаем tpl.id-шаблона — зачем узнаете далее.
В конечном итоге код нашего чанка (tpl) со сквозными элементами должен принять примерно такой код:
<!DOCTYPE html>
<html lang="[[++cultureKey]]">
<head>
<base href="[[++site_url]]">
<meta charset="[[++modx_charset]]">
<meta content="width=device-width, initial-scale=1.0" name="viewport">
<title>[[*longtitle]] | [[++site_name]]</title>
<meta content="[[*description]]" name="description">
<meta content="" name="keywords">
<!-- Favicons -->
<link href="templates/img/favicon.png" rel="icon">
<link href="templates/img/apple-touch-icon.png" rel="apple-touch-icon">
<!-- Google Fonts -->
<link href="https://fonts.googleapis.com/css?family=Open+Sans:300,300i,400,400i,600,600i,700,700i|Raleway:300,300i,400,400i,500,500i,600,600i,700,700i|Poppins:300,300i,400,400i,500,500i,600,600i,700,700i" rel="stylesheet">
<!-- Vendor CSS Files -->
<link href="templates/vendor/animate.css/animate.min.css" rel="stylesheet">
<link href="templates/vendor/bootstrap/css/bootstrap.min.css" rel="stylesheet">
<link href="templates/vendor/bootstrap-icons/bootstrap-icons.css" rel="stylesheet">
<link href="templates/vendor/boxicons/css/boxicons.min.css" rel="stylesheet">
<link href="templates/vendor/glightbox/css/glightbox.min.css" rel="stylesheet">
<link href="templates/vendor/swiper/swiper-bundle.min.css" rel="stylesheet">
<!-- Template Main CSS File -->
<link href="templates/css/style.css" rel="stylesheet">
</head>
<body>
<!-- ======= Top Bar ======= -->
<section id="topbar" class="d-flex align-items-center">
<div class="container d-flex justify-content-center justify-content-md-between">
<div class="contact-info d-flex align-items-center">
<i class="bi bi-envelope d-flex align-items-center"><a href="mailto:[[++email]]">[[++email]]</a></i>
<i class="bi bi-phone d-flex align-items-center ms-4"><span>[[++phone]]</span></i>
</div>
<div class="social-links d-none d-md-flex align-items-center">
[[++twitter:!empty=`<a href="[[++twitter]]" class="twitter"><i class="bi bi-twitter"></i></a>`]]
[[++facebook:!empty=`<a href="[[++facebook]]" class="facebook"><i class="bi bi-facebook"></i></a>`]]
[[++instagram:!empty=`<a href="[[++instagram]]" class="instagram"><i class="bi bi-instagram"></i></a>`]]
[[++linkedin:!empty=`<a href="[[++linkedin]]" class="linkedin"><i class="bi bi-linkedin"></i></i></a>`]]
</div>
</div>
</section>
<!-- ======= Header ======= -->
<header id="header" class="d-flex align-items-center">
<div class="container d-flex justify-content-between align-items-center">
<div class="logo">
<h1><a href="/">[[++site_name]]</a></h1>
</div>
<nav id="navbar" class="navbar">
<ul>
<li><a class="active" href="index.html">Home</a></li>
<li><a href="about.html">About</a></li>
<li><a href="services.html">Services</a></li>
<li><a href="portfolio.html">Portfolio</a></li>
<li><a href="team.html">Team</a></li>
<li><a href="pricing.html">Pricing</a></li>
<li><a href="blog.html">Blog</a></li>
<li class="dropdown"><a href="#"><span>Drop Down</span> <i class="bi bi-chevron-down"></i></a>
<ul>
<li><a href="#">Drop Down 1</a></li>
<li class="dropdown"><a href="#"><span>Deep Drop Down</span> <i class="bi bi-chevron-right"></i></a>
<ul>
<li><a href="#">Deep Drop Down 1</a></li>
<li><a href="#">Deep Drop Down 2</a></li>
<li><a href="#">Deep Drop Down 3</a></li>
<li><a href="#">Deep Drop Down 4</a></li>
<li><a href="#">Deep Drop Down 5</a></li>
</ul>
</li>
<li><a href="#">Drop Down 2</a></li>
<li><a href="#">Drop Down 3</a></li>
<li><a href="#">Drop Down 4</a></li>
</ul>
</li>
<li><a href="contact.html">Contact</a></li>
</ul>
<i class="bi bi-list mobile-nav-toggle"></i>
</nav><!-- .navbar -->
</div>
</header><!-- End Header -->
[[*id:is=`1`:then=`[[$hero_section]]`]]
<main id="main">
[[$tpl.[[*template]]]]
</main><!-- End #main -->
<!-- ======= Footer ======= -->
<footer id="footer">
<div class="footer-newsletter">
<div class="container">
<div class="row">
<div class="col-lg-6">
<h4>Новостная рассылка</h4>
<p>Никакого спама, только полезный контент!</p>
</div>
<div class="col-lg-6">
<form action="" method="post">
<input type="email" name="email"><input type="submit" value="Подписаться">
</form>
</div>
</div>
</div>
</div>
<div class="footer-top">
<div class="container">
<div class="row">
<div class="col-lg-3 col-md-6 footer-links">
<h4>Полезные ссылки</h4>
<ul>
<li><i class="bx bx-chevron-right"></i> <a href="#">Home</a></li>
<li><i class="bx bx-chevron-right"></i> <a href="#">About us</a></li>
<li><i class="bx bx-chevron-right"></i> <a href="#">Services</a></li>
<li><i class="bx bx-chevron-right"></i> <a href="#">Terms of service</a></li>
<li><i class="bx bx-chevron-right"></i> <a href="#">Privacy policy</a></li>
</ul>
</div>
<div class="col-lg-3 col-md-6 footer-links">
<h4>Наши услуги</h4>
<ul>
<li><i class="bx bx-chevron-right"></i> <a href="#">Web Design</a></li>
<li><i class="bx bx-chevron-right"></i> <a href="#">Web Development</a></li>
<li><i class="bx bx-chevron-right"></i> <a href="#">Product Management</a></li>
<li><i class="bx bx-chevron-right"></i> <a href="#">Marketing</a></li>
<li><i class="bx bx-chevron-right"></i> <a href="#">Graphic Design</a></li>
</ul>
</div>
<div class="col-lg-3 col-md-6 footer-contact">
<h4>Контактная информация</h4>
<p>
A108 Adam Street <br>
New York, NY 535022<br>
United States <br><br>
<strong>Телефон:</strong> +1 5589 55488 55<br>
<strong>Email:</strong> info@example.com<br>
</p>
</div>
<div class="col-lg-3 col-md-6 footer-info">
<h3>About Eterna</h3>
<p>Cras fermentum odio eu feugiat lide par naso tierra. Justo eget nada terra videa magna derita valies darta donna mare fermentum iaculis eu non diam phasellus.</p>
<div class="social-links mt-3">
[[++twitter:!empty=`<a class="twitter" href="[[++twitter]]"><i class="bx bxl-twitter"></i></a>`]]
[[++facebook:!empty=`<a class="facebook" href="[[++facebook]]"><i class="bx bxl-facebook"></i></a>`]]
[[++instagram:!empty=`<a class="instagram" href="[[++instagram]]"><i class="bx bxl-instagram"></i></a>`]]
[[++skype:!empty=`<a class="google-plus" href="[[++skype]]"><i class="bx bxl-skype"></i></a>`]]
[[++linkedin:!empty=`<a class="linkedin" href="[[++linkedin]]"><i class="bx bxl-linkedin"></i></i></a>`]]
</div>
</div>
</div>
</div>
</div>
<div class="container">
<div class="copyright">
© Copyright <strong><span>[[++site_name]]</span></strong>. Все права защищены
</div>
</div>
</footer><!-- End Footer -->
<a href="#" class="back-to-top d-flex align-items-center justify-content-center"><i class="bi bi-arrow-up-short"></i></a>
<!-- Vendor JS Files -->
<script src="templates/vendor/purecounter/purecounter_vanilla.js"></script>
<script src="templates/vendor/bootstrap/js/bootstrap.bundle.min.js"></script>
<script src="templates/vendor/glightbox/js/glightbox.min.js"></script>
<script src="templates/vendor/isotope-layout/isotope.pkgd.min.js"></script>
<script src="templates/vendor/swiper/swiper-bundle.min.js"></script>
<script src="templates/vendor/waypoints/noframework.waypoints.js"></script>
<script src="templates/vendor/php-email-form/validate.js"></script>
<!-- Template Main JS File -->
<script src="templates/js/main.js"></script>
</body>
</html>
Создаем дополнительные шаблоны
Пока создадим только 1 шаблон, для обычных статических страниц: о компании, политика конфиденциальности, контакты и т.п.. За основу возьмем к примеру файл team.html.
Создайте новый шаблон с именем Статика и вызовите в нем чанк tpl
(в котором хранятся сквозные элементы) и сохраните его.
Теперь создаем чанк с именем tpl.2 (где 2 — это id только, что созданного шаблона) и помещаем в него код который находится между в блоке main.
Теперь модернизируем секцию breadcrumbs, она примет вид:
<!-- ======= Breadcrumbs ======= -->
<section id="breadcrumbs" class="breadcrumbs">
<div class="container">
<ol>
<li><a href="/">Главная</a></li>
<li>[[*pagetitle]]</li>
</ol>
<h2>[[*pagetitle]]</h2>
</div>
</section><!-- End Breadcrumbs -->
Ее в принципе можно отправить в отдельный чанк: breadcrumbs. И вызвать чанке со сквозными элементами (tpl), вот такой конструкцией: [[*id:is=`1`:else=`[[$breadcrumbs]]`]]
— выводим чанк на всех страницах кроме главной.
Теперь выкинем все лишнее (в данном случае блоки с командой) из следующей секции с контентом и выведем поле контента, в конечном итоге получим следующий код чанка (tpl.2):
<section id="team" class="team">
<div class="container">
[[*content]]
</div>
</section>
Использование Сниппетов
MODX предлагает много динамики из коробки, и Сниппеты способ расширить эту динамику. Мы можем их писать сами, даже если вы не знаете PHP, можно воспользоваться к примеру чатом gpt (есть бесплатные боты в телеге, вот пример запроса и что он выдал):
Может не идеально, но с виду рабочий. Давайте попробуем его вывести, создаем сниппет с именем year и выше приведенным кодом:
<?php
// Получаем текущий год
$currentYear = date("Y");
// Указываем год, с которого начинается копирайтинг
$startYear = 2010;
// Если текущий год совпадает с начальным годом, выводим только один год
if ($currentYear == $startYear) {
echo $currentYear;
} else {
// Иначе выводим года в формате "2010 - 2021"
echo $startYear . " - " . $currentYear;
}
?>
И вызовем его в копирайтинге:
Переходим на сайт и проверяем:
Все работает, единственное мне не особо нравится, то что год создания (фирмы или сайта) нужно менять непосредственно в коде сниппета, модифицируем его, чтобы можно было задавать данный параметр при вызове сниппета:
<?php
$currentYear = date("Y");
if($currentYear == $startYear) {
return $currentYear;
} else {
return ''.$startYear.' – '.$currentYear.'';
}
Теперь его можно вызывать так: [[year? &startYear=`2022`]]
.
Исчерпали весь базовый функционал, что дальше?
На самом деле исчерпали не все, и рассмотрели лишь базовые принципы интеграции. При помощи сниппетов или плагинов можно напрограммировать на PHP кучу всего. Но мы пойдем по пути готовых решений — будем устанавливать дополнения (многие из которых включают в себя готовые сниппеты) и сажать остатки кода на них.
Сажать сложные элементы будем на MIGX: слайдеры, однотипные блоки состоящие из многих полей, в общем все то что у главной страницы в несквозных элементах.
А вот для многого остального, нужно создать ресурсы, из них будет строится меню, собираться некоторые блоки (например вывод услуг или статей на главной) и так далее. В общем создайте пока пустые статические страницы сайта (о компании, услуги, портфолио, контакты и т.п.) с новым шаблоном Статика.
И переходите к следующему уроку: создание контактных форм при помощи связки компонентов Formit + FetchIt.