PageBlocks. Интеграция шаблона Snow на MODX
        Всем привет.
Данным уроком хочу показать как можно легко и быстро интегрировать шаблон на MODX, надеюсь будет полезно. Забегая наперед, у меня получилось интегрировать сайт за 50 минут.
Для урока выбрал бесплатный шаблон Snow, он включает в себя главную страницу, 2 страницы портфолио и 2 страницы блога. А основным компонентом для интеграции будет PageBlocks.

1. Устанавливаем MODx
2. Переименовываем файл ht.access на .htaccess
3. Устанавливаем компоненты:

Страницы About и Contact — это ссылки на соответствующие блоки на главной странице.
Заменяем код главного шаблона на
Создаем чанки:
head:
header:
footer:

Структура блока:

Добавляем блок на страницу:

Поздравляю! Мы только что создали первый блок, надеюсь все было понятно. Идем дальше.

Здесь, все очень просто создаем блок с 2 полями: заголовок и контент, поэтому детально разбирать его не будем.

Структура:


Структура:
Коллекция — это создание однотипных блоков. Если блок имеет поля pagetitle, template и alias, то он будет привязан к ресурсу, который будет создан после создания блока. И все совпадающие поля синхронизируются в обоих направлениях. То есть, изменили поле в блоке и в ресурсе соответствующее поле тоже будет изменено и наоборот.
Шаг 1. Создаем блок для коллекции:
Поля:

Чанк work:
Шаг 2. Создаем коллекцию для наших работ.
Показывать коллекцию будем только в ресурсе c id 4 (Portfolio).

Шаг 3. Заполняем коллекцию.

Шаг 4. Создаем блок, в котором будем выводить нашу коллекцию.
Если вернуться в самое начало к блоку Portfolio, то нам нужны 2 поля — заголовок и описание.

Чанк projects

Здесь делаем по аналогии с блоком Features
Шаг 1. Создаем таблицу с полями: content и author
Шаг 2. Создаем блок в полями bg и reviews (ранее созданная таблица)
Чанк reviews:

Блок состоит только из логотипов, поэтому создаем блок с одним полем — галерея.

Чанк partners:
Добавляем логотипы:


Данный блог аналогичен блоку Portfolio. В итоге должно получиться так:

Чанк latest-blog
Чанк blog:

Структура:

Чанк contacts:
Чанк form.contact
Чанк email.contact:

Чанк portfolio-single
Чанк blog-single
Вот и все, сайт готов! Кому понравилось ставьте лайк.
Ссылка на сайт
    
    
                                                        Данным уроком хочу показать как можно легко и быстро интегрировать шаблон на MODX, надеюсь будет полезно. Забегая наперед, у меня получилось интегрировать сайт за 50 минут.
Для урока выбрал бесплатный шаблон Snow, он включает в себя главную страницу, 2 страницы портфолио и 2 страницы блога. А основным компонентом для интеграции будет PageBlocks.

Шаг 1. Подготовка
1. Устанавливаем MODx
2. Переименовываем файл ht.access на .htaccess
3. Устанавливаем компоненты:
- PageBlocks (конструктор блоков)
 - Ace (редактор кода)
 - TinyMCE Rich Text Editor (визуальный редактор)
 - pdoTools (набор удобных сниппетов)
 - SocialNetworks (для соц. сетей)
 - FormIt (обработчик форм для MODX)
 - AjaxForm (отправка форм через Ajax)
 
- Включаем дружеские url (friendly_urls)
 - Включаем псевдоним родителя в построении uri (use_alias_path)
 - Включаем Fenom на страницах (pdotools_fenom_parser)
 - Включаем Fenom в чанках (pdotools_fenom_default)
 - Разрешаем доступ к объектам MODX и PdoTools (pdotools_fenom_modx)
 - Отключение доступа к странице по id (request_method_strict = Да)
 
Шаг 2. Создаем страницы

Страницы About и Contact — это ссылки на соответствующие блоки на главной странице.
Шаг 3. Настройка шаблона
Заменяем код главного шаблона на
<!DOCTYPE html>
<html lang="en">
<head>
    {block 'head'}
        {insert 'head'}
    {/block}
</head>
<body>
    {insert 'header'}
    {insert 'navbar-mobile'}
    
    <div class="nk-main">
        {block 'blocks'}
            {'!PageBlocks' | snippet}
        {/block}
        {block 'content'}
            {$_modx->resource.content}
        {/block}
        {insert 'footer'}
    </div>
    
    <script src="/assets/js/combined.js"></script>
</body>
</html>Создаем чанки:
head:
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>{$_modx->resource.pagetitle} | {'site_name' | config}</title>
<meta name="description" content="{$_modx->resource.description}">
<link rel="icon" type="image/png" href="/assets/images/favicon.png">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- Google Fonts -->
<link href="https://fonts.googleapis.com/css?family=Playfair+Display:400,400i,700,700i%7cWork+Sans:400,500,700" rel="stylesheet" type="text/css">
<link rel="stylesheet" href="/assets/css/combined.css">header:
<header class="nk-header{if $_modx->resource.id != 1} nk-header-opaque{/if}">
    <nav class="nk-navbar nk-navbar-top{if $_modx->resource.id == 1} nk-navbar-sticky nk-navbar-transparent nk-navbar-white-text-on-top{/if}">
        <div class="container">
            <div class="nk-nav-table">
                <a href="/" class="nk-nav-logo">
                    <img src="/assets/images/logo-light.svg" alt="" width="85" class="nk-nav-logo-onscroll">
                    <img src="/assets/images/logo.svg" alt="" width="85">
                </a>
                
                {'!pdoMenu' | snippet: [
                    'parents' => 0,
                    'tplOuter' => '@INLINE <ul {$classes} data-nav-mobile="#nk-nav-mobile">{$wrapper}</ul>',
                    'outerClass' => 'nk-nav nk-nav-right hidden-md-down',
                    'scheme' => 'full',
                ]}
                <ul class="nk-nav nk-nav-right nk-nav-icons">
                    <li class="single-icon hidden-lg-up">
                        <a href="#" class="nk-navbar-full-toggle">
                            <span class="nk-icon-burger">
                                <span class="nk-t-1"></span>
                                <span class="nk-t-2"></span>
                                <span class="nk-t-3"></span>
                            </span>
                        </a>
                    </li>
                </ul>
            </div>
        </div>
    </nav>
</header>footer:
<footer class="nk-footer">
    <div class="nk-footer-cont">
        <div class="container text-xs-center">
            <div class="nk-footer-social">
                {'!SocialNetworks' | snippet: [
                    'fontawesome' => 'none',
                    'outerClass' => '',
                    'tpl' => '@INLINE <li><a href="{$link}" target="_blank" title="{$name}"><i class="fa fa-{$icon}"></i></a></li>',
                ]}
            </div>
            <div class="nk-footer-text">
                <p>{'' | date: 'Y'} © {'site_name' | config}</p>
            </div>
        </div>
    </div>
</footer>Шаг 4. Создаем блоки
1. Блок Hero

Структура блока:
- фон блока (bg)
 - подзаголовок (subtitle)
 - заголовок (title)
 - заголовок с курсивным начертанием (title_em)
 

Добавляем блок на страницу:

Поздравляю! Мы только что создали первый блок, надеюсь все было понятно. Идем дальше.
2. Блок About

Здесь, все очень просто создаем блок с 2 полями: заголовок и контент, поэтому детально разбирать его не будем.
3. Блок Features

Структура:
- фон (bg)
 - таблица преимущества (features)
 
- Иконка (icon)
 - Число (num)
 - Заголовок (title)
 

4. Блок Portfolio

Структура:
- Заголовок (title)
 - Описание (description)
 - Работы (будет выводиться коллекция)
 
Коллекция — это создание однотипных блоков. Если блок имеет поля pagetitle, template и alias, то он будет привязан к ресурсу, который будет создан после создания блока. И все совпадающие поля синхронизируются в обоих направлениях. То есть, изменили поле в блоке и в ресурсе соответствующее поле тоже будет изменено и наоборот.
Шаг 1. Создаем блок для коллекции:
Поля:
- Превью (img)
 - Заголовок (pagetitle)
 - Тег (tag)
 - Шаблон (template)
 - Псевдоним (alias)
 

Чанк work:
<div class="nk-isotope-item" data-filter="{$tag}">
    <div class="nk-portfolio-item nk-portfolio-item-square nk-portfolio-item-info-style-1">
        <a href="{$uri}" class="nk-portfolio-item-link"></a>
        <div class="nk-portfolio-item-image">
            <div style="background-image: url(/{$img});"></div>
        </div>
        <div class="nk-portfolio-item-info nk-portfolio-item-info-center text-xs-center">
            <div>
                <h2 class="portfolio-item-title h3">{$pagetitle}</h2>
                <div class="portfolio-item-category">{$tag}</div>
            </div>
        </div>
    </div>
</div>Шаг 2. Создаем коллекцию для наших работ.
Показывать коллекцию будем только в ресурсе c id 4 (Portfolio).

Шаг 3. Заполняем коллекцию.

Шаг 4. Создаем блок, в котором будем выводить нашу коллекцию.
Если вернуться в самое начало к блоку Portfolio, то нам нужны 2 поля — заголовок и описание.

Чанк projects
<div class="nk-box bg-white" id="projects">
    <div class="nk-gap-4 mt-5"></div>
    
    <h2 class="text-xs-center display-4">{$title}</h2>
    
    <div class="nk-gap mnt-6"></div>
    {if $content}
    <div class="container">
        <div class="row">
            <div class="col-lg-8 offset-lg-2">
                <div class="text-xs-center">{$content}
                </div>
            </div>
        </div>
    </div>
    {/if}
    <div class="nk-gap-2 mt-12"></div>
    <div class="container">
    <div class="nk-portfolio-list nk-isotope nk-isotope-3-cols">
        {'!PageBlocks' | snippet: [
            'rid' => 4,
            'collection' => 2,
            'limit' => 9
        ]}
    </div>
    </div>
    <div class="nk-gap-4 mt-15"></div>
</div>5. Блок Reviews

Здесь делаем по аналогии с блоком Features
Шаг 1. Создаем таблицу с полями: content и author
Шаг 2. Создаем блок в полями bg и reviews (ранее созданная таблица)
Чанк reviews:
<div class="nk-box bg-dark-1">
    <div class="bg-image bg-image-parallax" style="background-image: url({$bg});"></div>
    <div class="nk-gap-5 mnt-6"></div>
    <div class="nk-gap-3"></div>
    <div class="container-fluid">
        <!-- START: Carousel -->
        <div class="nk-carousel nk-carousel-all-visible text-white" data-autoplay="18000" data-dots="true">
            <div class="nk-carousel-inner">
                {foreach $reviews as $review}
                <div>
                    <div>
                        <blockquote class="nk-blockquote-style-1 text-white">
                            {$review.content}
                            <cite>{$review.author}</cite>
                        </blockquote>
                        <div class="nk-gap-3 mt-10"></div>
                    </div>
                </div>
                {/foreach}
            </div>
        </div>
        <!-- END: Carousel -->
    </div>
    <div class="nk-gap-4 mt-3"></div>
</div>6. Блок Partners

Блок состоит только из логотипов, поэтому создаем блок с одним полем — галерея.

Чанк partners:
<div class="bg-white">
    <div class="container">
        <div class="nk-carousel-2 nk-carousel-x4 nk-carousel-no-margin nk-carousel-all-visible">
            <div class="nk-carousel-inner">
                {foreach $logos as $logo}
                <div>
                    <div>
                        <div class="nk-box-1">
                            <img src="{$logo.url}" alt="{$logo.title}" class="nk-img-fit">
                        </div>
                    </div>
                </div>
                {/foreach}
            </div>
        </div>
    </div>
</div>Добавляем логотипы:

7. Блок Latest blog

Данный блог аналогичен блоку Portfolio. В итоге должно получиться так:

Чанк latest-blog
<div class="nk-box bg-gray-1" id="blog">
    <div class="nk-gap-4 mt-5"></div>
    <h2 class="text-xs-center display-4">{$title}</h2>
    <div class="nk-gap mnt-6"></div>
    
    {if $content}
    <div class="container">
        <div class="row">
            <div class="col-lg-8 offset-lg-2">
                <div class="text-xs-center">{$content}
                </div>
            </div>
        </div>
    </div>
    {/if}
    <div class="nk-gap-2 mt-12"></div>
    <div class="container">
        <!-- START: Carousel -->
        <div class="nk-carousel-2 nk-carousel-x2 nk-carousel-no-margin nk-carousel-all-visible nk-blog-isotope" data-dots="true">
            <div class="nk-carousel-inner">
                
                {set $blogs = '!PageBlocks' | snippet: [
                    'rid' => 5,
                    'collection' => 3,
                    'limit' => 9,
                    'return' => 'json'
                ] | fromJSON}
                
                {foreach $blogs as $blog}
                <div>
                    <div>
                        <div class="pl-15 pr-15">
                            {$_modx->getChunk('blog', $blog)}
                        </div>
                        <div class="nk-gap-1"></div>
                    </div>
                </div>
                {/foreach}
            </div>
        </div>
        <!-- END: Carousel -->
    </div>
    <div class="nk-gap-5 mt-20"></div>
</div>Чанк blog:
<div class="nk-blog-post">
    <div class="nk-post-thumb">
        <a href="/{$uri}">
            <img src="/{$img}" alt="{$pagetitle|notags}" class="nk-img-stretch">
        </a>
        <div class="nk-post-category"><a href="/{$uri}">{$tag}</a></div>
    </div>
    <h2 class="nk-post-title h4"><a href="blog-single.html">{$pagetitle}</a></h2>
    <div class="nk-post-date">
        {$publishedon | date_format: '%d.%m.%Y'}
    </div>
    <div class="nk-post-text">
        <p>{$description}</p>
    </div>
</div>8. Блок Contacts

Структура:
- Заголовок (title)
 - Описание (content)
 - Адрес (address)
 - Телефон (phone)
 - Почта (email)
 - Факс (fax)
 

Чанк contacts:
<div class="container" id="contact">
    <div class="nk-gap-5"></div>
    <div class="row vertical-gap">
        <div class="col-lg-5">
            
            <h2 class="display-4">{$title}</h2>
            <div class="nk-gap mnt-3"></div>
            {$content}
            <ul class="nk-contact-info">
                {if $address}
                    <li><strong>Address:</strong> {$address}</li>
                {/if}
                
                {if $phone}
                    <li><strong>Phone:</strong> {$phone}</li>
                {/if}
                
                {if $email}
                    <li><strong>Email:</strong> {$email}</li>
                {/if}
                
                {if $fax}
                    <li><strong>Fax:</strong> {$fax}</li>
                {/if}
            </ul>
            
        </div>
        <div class="col-lg-7">
            
            {'!AjaxForm' | snippet: [
                'form' => 'form.contact',
                'hooks' => 'email',
                'emailTpl' => 'email.contact',
                'emailSubject' => 'Contacts',
                'emailTo' => 'Superboshnik@gmail.com',
                'emailFrom' => $_modx->config.emailsender,
                'emailFromName' => $_modx->config.site_name,
                'validate' => 'name:required,email:required,title:required,message:required',
                'validationErrorMessage' => 'В форме содержатся ошибки!',
                'successMessage' => 'Сообщение успешно отправлено',
            ]}
            
        </div>
    </div>
    <div class="nk-gap-5"></div>
</div>Чанк form.contact
<form action="{$_modx->resource.uri}"  method="post" class="nk-form nk-form-ajax">
    <div class="row vertical-gap">
        <div class="col-md-6">
            <input type="text" class="form-control" name="name" placeholder="Your Name">
        </div>
        <div class="col-md-6">
            <input type="email" class="form-control" name="email" placeholder="Your Email">
        </div>
    </div>
    <div class="nk-gap-1"></div>
    <input type="text" class="form-control" name="title" placeholder="Your Title">
    <div class="nk-gap-1"></div>
    <textarea class="form-control" name="message" rows="8" placeholder="Your Comment" aria-required="true"></textarea>
    <div class="nk-gap-1"></div>
    
    <button class="nk-btn" type="submit">Send Message</button>
</form>Чанк email.contact:
<ul>
    <li><b>Name:</b> {$name}</li>
    <li><b>Email:</b> {$email}</li>
    <li><b>Title:</b> {$title}</li>
    <li><b>Message:</b> {$message}</li>
</ul>Шаг 5. Создаем другие страницы
Страница Portfolio
На этой странице нам нужно вывести 9 последних работ из коллекции. Для вывода будем использовать сниппет pdoPage. В настройках ресурса отключаем html-редактор и вставляем код в поле content:<div id="pdopage">
    <div class="container">
        <!-- START: Filter -->
        <div class="nk-pagination nk-pagination-nobg nk-pagination-center">
            <a href="#nk-toggle-filter">
                <span class="nk-icon-squares"></span>
            </a>
        </div>
        <ul class="nk-isotope-filter">
            <li class="active" data-filter="*">All</li>
            <li data-filter="Branding">Branding</li>
            <li data-filter="Print">Print</li>
            <li data-filter="Photography">Photography</li>
            <li data-filter="Design">Design</li>
            <li data-filter="Mockup">Mockup</li>
        </ul>
        <!-- END: Filter -->
    
        <div class="nk-portfolio-list nk-isotope nk-isotope-3-cols rows">
            
            {'!pdoPage' | snippet: [
                'element' => 'PageBlocks',
                'sortby' => 'rank',
                'sortdir' => 'desc',
                'limit' => 9,
                'ajaxMode' => 'button',
                'ajaxTplMore' => '@INLINE <div class="nk-gap-4"></div><div class="nk-pagination nk-pagination-center btn-more"><a href="#">Load More Works</a></div>',
                'where' => [
                    'resource_id' => $_modx->resource.id,
                    'collection_id' => 2,
                    'active' => 1,
                ]
            ]}
            
        </div>
        <div class="nk-gap-4"></div>
    </div>
    {'page.nav' | placeholder}
</div>Внутренняя страница работы
Добавляем блок:
Чанк portfolio-single
<div class="container">
    <div class="nk-portfolio-single">
        <div class="nk-gap-4 mb-14"></div>
        <h1 class="nk-portfolio-title display-4">{$title ?: $_modx->resource.pagetitle}</h1>
        <div class="row vertical-gap">
            <div class="col-lg-8">
                <div class="nk-portfolio-info">
                    <div class="nk-portfolio-text">
                        {$content}
                    </div>
                </div>
            </div>
            <div class="col-lg-4">
                <table class="nk-portfolio-details">
                    {if $client}
                    <tr>
                        <td>
                            <strong>Client:</strong>
                        </td>
                        <td>{$client}</td>
                    </tr>
                    {/if}
                    {if $date}
                    <tr>
                        <td>
                            <strong>Date:</strong>
                        </td>
                        <td>{$date | date_format: '%d.%m.%Y'}</td>
                    </tr>
                    {/if}
                </table>
            </div>
        </div>
        <div class="nk-gap-4 mt-14"></div>
    </div>
</div>
{if $img}
    <img class="nk-img-fit" src="/{$img}">
{/if}
<div class="nk-pagination nk-pagination-center">
    <div class="container">
        
        {'!pdoNeighbors' | snippet: [
            'tplWrapper' => '@INLINE {$prev}<a class="nk-pagination-center" href="#"><span class="nk-icon-squares"></span></a>{$next}',
            'tplPrev' => '@INLINE <a class="nk-pagination-prev" href="/{$uri}"><span class="pe-7s-angle-left"></span> Previous Work</a>',
            'tplNext' => '@INLINE <a class="nk-pagination-next" href="/{$uri}">Next Work <span class="pe-7s-angle-right"></span></a>',
        ]}
    </div>
</div>Страница Blog и внутренняя страница
Делаем по аналогии с портфолио.Чанк blog-single
{if $img}
<div class="nk-header-title nk-header-title-lg">
    <div class="bg-image">
        <div style="background-image: url(/{$img});"></div>
    </div>
    <div class="nk-header-table">
        <div class="nk-header-table-cell">
            <div class="container">
            </div>
        </div>
    </div>
</div>
{/if}
// Здесь стоит остановится на одном моменте. 
// На внутренней страницы блога мы должны вывести тег статьи, но мы не расширяли модель ресурса, 
// поэтому это поле находиться только в блоке и чтобы получить все поля используем такую конструкцию:
{set $block = '!PageBlocks' | snippet: [
    'object_id' => $_modx->resource.id,
    'return' => 'json',
] | fromJSON}
<div class="container">
    <div class="row">
        <div class="col-lg-8 offset-lg-2">
            <div class="nk-gap-4"></div>
            <!-- START: Post -->
            <div class="nk-blog-post nk-blog-post-single">
                <h1 class="display-4">{$title ?: $_modx->resource.pagetitle}</h1>
                <div class="nk-post-meta">
                    <div class="nk-post-date">{$_modx->resource.publishedon}</div>
                    
                    // И теперь у нас есть доступ к полям блока и выводим тег:
                    <div class="nk-post-category"><a href="#"{$block.tag}</a></div>
                </div>
                <!-- START: Post Text -->
                <div class="nk-post-text">
                    {$content}
                </div>
                <!-- END: Post Text -->
            </div>
            <!-- END: Post -->
            <div class="nk-gap-3"></div>
        </div>
    </div>
</div>
<div class="nk-pagination nk-pagination-center">
    <div class="container">
        {'!pdoNeighbors' | snippet: [
            'tplWrapper' => '@INLINE {$prev}<a class="nk-pagination-center" href="#"><span class="nk-icon-squares"></span></a>{$next}',
            'tplPrev' => '@INLINE <a class="nk-pagination-prev" href="/{$uri}"><span class="pe-7s-angle-left"></span> Previous Work</a>',
            'tplNext' => '@INLINE <a class="nk-pagination-next" href="/{$uri}">Next Work <span class="pe-7s-angle-right"></span></a>',
        ]}
    </div>
</div>Вот и все, сайт готов! Кому понравилось ставьте лайк.
Ссылка на сайт
            
                Поблагодарить автора            
            
                 Отправить деньги            
        
        
            Комментарии: 11
                Вот и первый урок в новом разделе «Уроки». Александр Красавчик!
Кстати если кто-то не заметил — у нас созданы два новых раздела.
Уроки и обзоры. Сделано это в рамках задачи по популяризации MODX.
В рамках раздела обзоры — хотим дать больше контента и свежего взгляда на популярные и не очень компоненты, информации о которых не хватает!
В рамках раздела уроки — планируем рассказывать о «современных» технологиях разработки, объясняя почему сниппет IF — который до сих пор встречается, это плохо!
                    Кстати если кто-то не заметил — у нас созданы два новых раздела.
Уроки и обзоры. Сделано это в рамках задачи по популяризации MODX.
В рамках раздела обзоры — хотим дать больше контента и свежего взгляда на популярные и не очень компоненты, информации о которых не хватает!
В рамках раздела уроки — планируем рассказывать о «современных» технологиях разработки, объясняя почему сниппет IF — который до сих пор встречается, это плохо!
                За такие уроки плюсики должны умножаться на 5            
                    
                Согласен, материал отличный! Не исключено, что так и сделаем. Но раздел скорее всего будет закрытым и писать в него можно будет только при определенном рейтинге или каком то другом ограничении. Планов много — добраться бы. 
Кстати кому интересно узнать о планах развития MODX.pro?
                    Кстати кому интересно узнать о планах развития MODX.pro?
Кстати кому интересно узнать о планах развития MODX.pro?Интересно! Ждем анонс.
                Компонент реально крутой получился, уже перерос компонент от Марка из modmore. Единственное чего не хватает, возможности указывать файловые чанки, снова нужно писать код в админке.            
                    
                а что нельзя в чанке написать 
                    {include "file:chunks/chunk.tpl"} ??            
                Можно, а смысл? В чанке вызывать файловый чанк. Скоро будет поддержка файловых чанков.            
                    
                Т.е. код оставищь в чанке и можно будет указать путь, как у MODX?            
                    
                Ага, будет создаваться файловых чанк            
                    
                Кто-то пробовал делать поиск по сайту на этом компоненте?            
                    
                Ну сам себе и отвечу, компонент AdvSearch прекрасно ищет по json PageBlocks и MigX            
                    
                            Авторизуйтесь или зарегистрируйтесь, чтобы оставлять комментарии.