Перенос готовой верстки (шаблона)
Каждый html шаблон состоит из определенного набора файлов, обычно это html, css, js файлы и изображения. Также могут быть шрифты, scss файлы, php обработчики и т.д.
Скачать шаблон который используется в данном уроке, можно здесь: Шаблоны для MODX.
Для интеграции дизайна нам обычно нужно перенести на хостинг все файлы кроме html и php. В данном случае все, что нам нужно лежит в папке assets:
Закачаем все файлы из папки assets
в директорию assets
. Сделать это можно при помощи файлового менеджера хостинга или через ftp/sftp. В конечном итоге получаем следующее:
Теперь можно отредактировать базовый шаблон, для этого в дереве ресурсов перейдите во вкладку «Элементы» — «Шаблоны» и отредактируем «Начальный шаблон».
Как вы видите в начальном шаблоне присутствует синтаксис MODX: [[*name]]
— поля ресурсов и TV, [[++name]]
— системные настройки. Мы все это будем изучать его по мере разработки сайта, а сейчас можете удалить весь код шаблона.
Чтобы код MODX шаблонов подсвечивался установите дополнение Ace.
Теперь откройте код главной страницы html шаблона — обычно это файл index.html (делать это лучше при помощи редакторов кода) скопируйте и вставьте его в место стандартного кода начального шаблона. Затем сохраните шаблон.
Откройте главную страницу, она должна стать такой же как у шаблона.
Если у вас весь код кривой, значит вы что-то не закачали.
Интеграция html верстки с CMS
Интеграция html верстки с CMS — это процесс объединения дизайна и верстки сайта (html, CSS, JavaScript) с системой управления контентом (CMS), в нашем случае с MODX. Это позволяет управлять контентом сайта через интерфейс CMS, без необходимости вручную изменять код сайта.
Иными словами нам нужно превратить статический код в динамический, чтобы значительно упростить процесс управления контентом и обновления сайта, а также при необходимости создавать более сложные и функциональные сайты.
Интеграция верстки в MODX часто начинается с определения того, какие элементы сайта обычно повторяются от страницы к странице. Если открыть все наши html файлы шаблоны и посмотреть на них, то вы увидите что у всех есть повторяющиеся элементы: шапка с навигацией (header), хлебные крошки (на всех страницах кроме главной), футер.
Это все так сказать сквозные элементы, их можно вынести в отдельные чанки.
Использование чанков
Чанки способ предложить управления повторяющимся контентом в одном месте. В приведенном выше примере шаблона есть статическая навигация в верхнем и нижнем колонтитулах, это может стать проблемой, если возникла необходимость изменить текст для одной из этих ссылок. Вместо изменения текста в каждом шаблоне и десинхронизации риска было бы предпочтительно обновить его один раз, и это изменение отразится на всех шаблонах. Мы можем сделать это, используя чанки.
Сделаем хитрую систему чанков: создаем чанк tpl
и переносим в него весь код из начального шаблона, вместо него выводим созданный чанк.
Далее вырезаем из чанка чанк tpl
все кроме сквозных элементов (в дaнном случае все что находится между <main class="main"> ... </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>
<meta name="description" content="[[*description]]">
Так же мы можем создать свои системные настройки, сделать это проще всего при помощи дополнения ClientConfig, установите его и создайте там настройки: телефон, email, адрес, соц. сети и т.д.
Затем выведите их в нужных частях шаблона.
Использование фильтров и модификаторов
Усложним логику вывода чанков и стандартных полей, системных настроек при помощи фильтров и модификаторов.
Немного усложним вывод title
, сделаем его таким:
[[*longtitle:default=`[[*pagetitle]]`]]
— если заполнен расширенный заголовок то выводим его, в противном слугае выводим заголовок.
Добавим meta robots:
<meta name="robots" content="[[*searchable:is=`1`:then=`index, follow`:else=`noindex, nofollow`]]">
Модифицируем вызов чанка tpl.1
:
[[$tpl.[[*template]]]]
В данном случае мы в зависимости от шаблона подключаем tpl.id-шаблона — зачем узнаете далее.
В конечном итоге код нашего чанка (tpl) со сквозными элементами должен принять примерно такой код:
<!DOCTYPE html>
<html lang="[[++cultureKey]]">
<head>
<base href="[[++site_url]]">
<meta charset="[[++modx_charset]]">
<meta name="robots" content="[[*searchable:is=`1`:then=`index, follow`:else=`noindex, nofollow`]]">
<meta content="width=device-width, initial-scale=1.0" name="viewport">
<title>[[*longtitle]] | [[++site_name]]</title>
<meta name="description" content="[[*description]]">
<meta name="keywords" content="">
<!-- Favicons -->
<link href="assets/img/favicon.png" rel="icon">
<link href="assets/img/apple-touch-icon.png" rel="apple-touch-icon">
<!-- Fonts -->
<link href="https://fonts.googleapis.com" rel="preconnect">
<link href="https://fonts.gstatic.com" rel="preconnect" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Open+Sans:ital,wght@0,300;0,400;0,500;0,600;0,700;0,800;1,300;1,400;1,500;1,600;1,700;1,800&family=Poppins:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&family=Raleway:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&display=swap" rel="stylesheet">
<!-- Vendor CSS Files -->
<link href="assets/vendor/bootstrap/css/bootstrap.min.css" rel="stylesheet">
<link href="assets/vendor/bootstrap-icons/bootstrap-icons.css" rel="stylesheet">
<link href="assets/vendor/aos/aos.css" rel="stylesheet">
<link href="assets/vendor/swiper/swiper-bundle.min.css" rel="stylesheet">
<link href="assets/vendor/glightbox/css/glightbox.min.css" rel="stylesheet">
<!-- Main CSS File -->
<link href="assets/css/main.css" rel="stylesheet">
</head>
<body class="index-page">
<header id="header" class="header sticky-top">
<div class="topbar d-flex align-items-center dark-background">
<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-x"></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></a>`]]
</div>
</div>
</div><!-- End Top Bar -->
<div class="branding">
<div class="container position-relative d-flex align-items-center justify-content-between">
<a href="/" class="logo d-flex align-items-center">
<!-- Uncomment the line below if you also wish to use an image logo -->
<!-- <img src="assets/img/logo.png" alt=""> -->
<h1 class="sitename">[[++site_name]]<br></h1>
</a>
<nav id="navmenu" class="navmenu">
<ul>
<li><a href="index.html" class="active">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>Dropdown</span> <i class="bi bi-chevron-down toggle-dropdown"></i></a>
<ul>
<li><a href="#">Dropdown 1</a></li>
<li class="dropdown"><a href="#"><span>Deep Dropdown</span> <i class="bi bi-chevron-down toggle-dropdown"></i></a>
<ul>
<li><a href="#">Deep Dropdown 1</a></li>
<li><a href="#">Deep Dropdown 2</a></li>
<li><a href="#">Deep Dropdown 3</a></li>
<li><a href="#">Deep Dropdown 4</a></li>
<li><a href="#">Deep Dropdown 5</a></li>
</ul>
</li>
<li><a href="#">Dropdown 2</a></li>
<li><a href="#">Dropdown 3</a></li>
<li><a href="#">Dropdown 4</a></li>
</ul>
</li>
<li><a href="contact.html">Contact</a></li>
</ul>
<i class="mobile-nav-toggle d-xl-none bi bi-list"></i>
</nav>
</div>
</div>
</header>
<main class="main">
[[$tpl.[[*template]]]]
</main>
<footer id="footer" class="footer position-relative dark-background">
<div class="footer-newsletter">
<div class="container">
<div class="row justify-content-center text-center">
<div class="col-lg-6">
<h4>Join Our Newsletter</h4>
<p>Subscribe to our newsletter and receive the latest news about our products and services!</p>
<form action="forms/newsletter.php" method="post" class="php-email-form">
<div class="newsletter-form"><input type="email" name="email"><input type="submit" value="Subscribe"></div>
<div class="loading">Loading</div>
<div class="error-message"></div>
<div class="sent-message">Your subscription request has been sent. Thank you!</div>
</form>
</div>
</div>
</div>
</div>
<div class="container footer-top">
<div class="row gy-4">
<div class="col-lg-4 col-md-6 footer-about">
<a href="/" class="d-flex align-items-center">
<span class="sitename">[[++site_name]]</span>
</a>
<div class="footer-contact pt-3">
<p>A108 Adam Street</p>
<p>New York, NY 535022</p>
<p class="mt-3"><strong>Phone:</strong> <span>[[++phone]]</span></p>
<p><strong>Email:</strong> <span>[[++email]]</span></p>
</div>
</div>
<div class="col-lg-2 col-md-3 footer-links">
<h4>Useful Links</h4>
<ul>
<li><i class="bi bi-chevron-right"></i> <a href="#">Home</a></li>
<li><i class="bi bi-chevron-right"></i> <a href="#">About us</a></li>
<li><i class="bi bi-chevron-right"></i> <a href="#">Services</a></li>
<li><i class="bi bi-chevron-right"></i> <a href="#">Terms of service</a></li>
</ul>
</div>
<div class="col-lg-2 col-md-3 footer-links">
<h4>Our Services</h4>
<ul>
<li><i class="bi bi-chevron-right"></i> <a href="#">Web Design</a></li>
<li><i class="bi bi-chevron-right"></i> <a href="#">Web Development</a></li>
<li><i class="bi bi-chevron-right"></i> <a href="#">Product Management</a></li>
<li><i class="bi bi-chevron-right"></i> <a href="#">Marketing</a></li>
</ul>
</div>
<div class="col-lg-4 col-md-12">
<h4>Follow Us</h4>
<p>Cras fermentum odio eu feugiat lide par naso tierra videa magna derita valies</p>
<div class="social-links d-flex">
[[++twitter:!empty=`<a href="[[++twitter]]"><i class="bi bi-twitter-x"></i></a>`]]
[[++facebook:!empty=`<a href="[[++facebook]]"><i class="bi bi-facebook"></i></a>`]]
[[++instagram:!empty=`<a href="[[++instagram]]"><i class="bi bi-instagram"></i></a>`]]
[[++linkedin:!empty=`<a href="[[++linkedin]]"><i class="bi bi-linkedin"></i></a>`]]
</div>
</div>
</div>
</div>
<div class="container copyright text-center mt-4">
<p>© <span>Copyright</span> <strong class="px-1 sitename">[[++site_name]]</strong> <span>All Rights Reserved</span></p>
</div>
</footer>
<!-- Scroll Top -->
<a href="#" id="scroll-top" class="scroll-top d-flex align-items-center justify-content-center"><i class="bi bi-arrow-up-short"></i></a>
<!-- Preloader -->
<div id="preloader"></div>
<!-- Vendor JS Files -->
<script src="assets/vendor/bootstrap/js/bootstrap.bundle.min.js"></script>
<script src="assets/vendor/php-email-form/validate.js"></script>
<script src="assets/vendor/aos/aos.js"></script>
<script src="assets/vendor/swiper/swiper-bundle.min.js"></script>
<script src="assets/vendor/purecounter/purecounter_vanilla.js"></script>
<script src="assets/vendor/waypoints/noframework.waypoints.js"></script>
<script src="assets/vendor/glightbox/js/glightbox.min.js"></script>
<script src="assets/vendor/imagesloaded/imagesloaded.pkgd.min.js"></script>
<script src="assets/vendor/isotope-layout/isotope.pkgd.min.js"></script>
<!-- Main JS File -->
<script src="assets/js/main.js"></script>
</body>
</html>
Создаем дополнительные шаблоны
Пока создадим только 1 шаблон, для обычных статических страниц: о компании, политика конфиденциальности, контакты и т.п.. За основу возьмем к примеру файл team.html
.
Создайте новый шаблон с именем Статика и вызовите в нем чанк tpl
(в котором хранятся сквозные элементы) и сохраните его.
Теперь создаем чанк с именем tpl.2 (где 2 — это id только, что созданного шаблона) и помещаем в него код который находится между в блоке main.
Теперь модернизируем секцию breadcrumbs, она примет вид:
<!-- Page Title -->
<div class="page-title" data-aos="fade">
<div class="container">
<nav class="breadcrumbs">
<ol>
<li><a href="/">Главная</a></li>
<li class="current">[[*pagetitle]]</li>
</ol>
</nav>
<h1>[[*pagetitle]]</h1>
</div>
</div><!-- End Page Title -->
Ее в принципе можно отправить в отдельный чанк: breadcrumbs. И вызвать чанке со сквозными элементами (tpl), вот такой конструкцией: [[*id:is=`1`:else=`[[$breadcrumbs]]`]]
— выводим чанк на всех страницах кроме главной.
Теперь выкинем все лишнее (в данном случае блоки с командой) из следующей секции с контентом и выведем поле контента, в конечном итоге получим следующий код чанка (tpl.2):
<section id="team" class="team section">
<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.
Большое спасибо за ресурс!
Здесь не совсем понятно откуда взялось tpl.1
Вот эта конструкция
[[$tpl.[[*template]]]]
подхватывает чанкиtpl.1
,tpl.2
,tpl.3
и т.д. Вот еще статью прочитайте https://web-revenue.ru/modx-revo/chanki — в ней описана такая же логика разбивки (возможно в ней более понятно объяснено).