MODX Revo ContentBlocks для бедных на основе MIGX

25.07.2019
7112

Всех приветствую, дорогие друзья! Сегодня мы с вами сделаем конструктор страниц для нашего MODX Revolution на основе бесплатного компонента MIGX. Данный способ реализации текстовой страницы я еще привык называть “правильным”, так как заказчик сам решает какой блок в какое место расположить и чем его наполнить.

Для начала определимся со стандартным набором блоков для нашего конструктора, посмотреть его вы сможете по ссылке https://dev3.dart.agency/oplata.html. Все блоки, которые там представлены вы можете использовать как душе угодно и формировать даже страницы – лендинги (собственно этот способ реализации, так и придумался).

Итак, начнем с первого экрана. Как правило, на страницах-лендингах содержится крупный баннер и оффер с формой. Так как нам не нужны будут хлебные крошки при использовании данного экрана, мы вынесем его отдельно от наших блоков. Для него мы создадим два TV-параметра: slider_firstblock (MIGX-слайдер, пример реализации можно посмотреть здесь) и firstblock (чекбокс отображать наш первый блок или нет). Подробную реализацию смотрите в видео к данной статье.

У меня slider_firstblock получился следующий. Вкладки формы:

[{"caption":"Слайд", "fields": [
    {"field":"header","caption":"Заголовок"},
    {"field":"alt","caption":"ALT атрибут"}, 
    {"field":"image","caption":"Изображение","inputTVtype":"image","description":"изображение не менее 1920x395"},
    {"field":"resid","caption":"ID ресурса для перехода"}
  ]
}]

Разметка колонок:

[{
  "header": "Заголовок", "sortable": "true", "dataIndex": "header"
},{
  "header": "ALT атрибут", "sortable": "true", "dataIndex": "alt"
},{
  "header": "Изображение", "sortable": "false", "dataIndex": "image","renderer": "this.renderImage"
},{
  "header": "ID ресурса для перехода", "sortable": "true", "dataIndex": "resid"
}]

Теперь, мы можем приступить к нашим блокам. Для начала создадим категорию “Блоки” и запомним ее идентификатор. У меня он получился – 41.

И перейдем к самому интересному, реализации конструктора страниц. Первым создадим TV-параметр block_types с типом ввода “Список с одиночным выбором”, а в поле “Возможные значения” укажем:

@SELECT `description`,`name` FROM `[[+PREFIX]]site_htmlsnippets` WHERE `category` = 41

Где 41 – идентификатор нашей категории “Блоки”. Параметры вывода должны стоять “По умолчанию” и шаблоны отмечать не нужно.

Конечно, нужно понимать, что в каждом нашем блоке есть подблоки, поэтому создадим TV-параметр blockitems с типом ввода MIGX. Вкладки формы:

[{"caption":"Элемент", "fields": [
    {"field":"title","caption":"Заголовок"}, 
    {"field":"descriptions","caption":"Текст под заголовком"}, 
    {"field":"icon","caption":"Иконка"}, 
    {"field":"image","caption":"Изображение","inputTVtype":"image"}, 
    {"field":"text","caption":"Текст","inputTVtype":"richtext"}, 
    {"field":"video","caption":"Видео"},
    {"field":"href","caption":"Ссылка"}
  ]
}]

Разметка колонок:

[{
  "header": "Заголовок", "sortable": "true", "dataIndex": "title"
}]

Обратите внимание на поле “descriptions”, оно названо так не случайно. Слово “description” зарезервировано.

Следующий наш шаг будет создание основного рабочего TV-параметра blocks c типом ввода “MIGX”. Вкладки формы:

[{"caption":"Блок", "fields": [
    {"field":"title","caption":"Заголовок"}, 
    {"field":"descriptions","caption":"Текст под заголовком"},
    {"field":"chunk","caption":"Тип блока","inputTV":"block_types"}, 
    {"field":"class","caption":"Класс"},
    {"field":"image","caption":"Изображение","inputTVtype":"image"},
    {"field":"video","caption":"Видео"}, 
    {"field":"gallery","caption":"Галерея","description":"Идентификатор галереи"},
    {"field":"text","caption":"Текст","inputTVtype":"richtext"}, 
    {"field":"elements","caption":"Элементы","inputTV":"blockitems"}
  ]
}]

Разметка колонок:

[{
  "header": "Заголовок", "sortable": "true", "dataIndex": "title"
},{
  "header": "Чанк", "sortable": "true", "dataIndex": "chunk"
}]

Обязательно отметьте здесь соответствующие рабочие шаблоны. Если вы посмотрите на данное TV-поле на странице ресурса, то увидите, что по сути у нас получился MIGX в MIGX’се. При заполнении, главное, не запутаться в таблицах.

Следующим шагом создадим два снипета, которые помогут нам при выводе наших блоков. Непосредственно сниппет по работе с MIGX get_sections.php (я работаю с файлами, вы можете создать в панели управления):

<?php
if(!$docid){
  $resource = $modx->resource;
}else{
  $resource = $modx->getObject("modResource", $docid);
}
if($tvname){
  $pdo = $modx->getService('pdoFetch');
  $output = '';
  $tvcontent = json_decode($resource->getTVValue($tvname), 1);
  foreach($tvcontent as $section){
	$output .= $pdo->getChunk($section["chunk"], $section);
  }
  echo $output;
}else{
  echo "ERROR: не указан TV!";
}

Снипет thumb_youtube.php, который будет брать миниатюры к видео с Youtube:

<?php
$url = $modx->getOption('url', $scriptProperties, false);
if($url){
  $param = parse_url($url);
  parse_str(parse_url($url, PHP_URL_QUERY), $parameters);
  return 'https://img.youtube.com/vi/'.$parameters[v].'/maxresdefault.jpg';
}else{
  return 'thumbYouTube snippet Error';
}

Класс! Теперь создадим чанки блоков (они обязательно должны быть в панели управления MODX). Конечно, у вас это могут быть другие чанки. Я же приведу примеры своих, основанных на Bootstrap 4. У всех чанков должна быть категория “Блоки”, которую мы с вами создавали в начале, и обязательно должно быть заполнено поле “описание”.

Простой чанк (имя: simpleBlockTpl, описание: Простой блок на всю ширину):

<section class="def-section {$class}" id="section_{$MIGX_id}">
    <div class="container">
        <h2>{$title}</h2>
        {if $subtitle}
            <div class="desc">{$subtitle}</div>
        {/if}
        {if $text}
            <div>{$text}</div>
        {/if}
    </div>
</section>

Видеогалерея (имя: videoBlockTpl, описание: Блок видеогалереи):

<section class="def-section video {$class}" id="section_{$MIGX_id}">
    <div class="container">
        <h2>{$title}</h2>
        {if $subtitle}
            <div class="desc">{$subtitle}</div>
        {/if}
        <div class="video-gallery">
            <div class="row">
                {if $elements}
                    {set $rows = json_decode($elements, true)}
                    {foreach $rows as $row}
                        <!-- item -->
                        <div class="col-sm-6 col-md-4">
                            <div class="item">
                                <a data-fancybox href="{$row.video}">
                                    <img src="{$_modx->runSnippet("@FILE snippets/thumb_youtube.php", ['url' => $row.video])}" alt="{$row.title | htmlent}">
                                </a>
                            </div>
                        </div>
                        <!-- / item -->
                    {/foreach}
                {/if}
            </div>
        </div>
        {if $text}
            <div class="desc">{$text}</div>
        {/if}
    </div>
</section>

Блок с кругляшами (имя: roundedBlockTpl, описание: Блок с кругляшами):

<section class="def-section for_who {$class}" id="section_{$MIGX_id}">
    <div class="container">
        <h2>{$title}</h2>
        {if $subtitle}
            <div class="desc">{$subtitle}</div>
        {/if}
        <div class="interiers">
            <div class="row justify-content-center">
                {if $elements}
                    {set $rows = json_decode($elements, true)}
                    {foreach $rows as $row}
                        <!-- item -->
                        <div class="col-lg-2 col-md-4 col-6">
                            <div class="item">
                                <div class="icon">
                                    {set $image = $_modx->runSnippet("phpthumbon",[
                                        "input" => "assets/files/"~$row.image,
                                        "options" => "w=200&h=200&zc=1&q=99"
                                    ])}
                                    <div class="img" style="background: url({$image}) no-repeat;"></div>
                                </div>
                                <div class="text">
                                    <span class="title">{$row.title}</span>
                                </div>
                            </div>
                        </div>
                        <!-- / item -->
                    {/foreach}
                {/if}
            </div>
        </div>
        {if $text}
            <div class="desc">{$text}</div>
        {/if}
    </div>
</section>

Блок в две колонки (имя: simpleHalfBlockTpl, описание: Блок в две колонки):

<section class="def-section {$class}" id="section_{$MIGX_id}">
    <div class="container">
        {if $title}
            <h2>{$title}</h2>
        {/if}
        {if $subtitle}
            <div class="desc">{$subtitle}</div>
        {/if}
        <div class="simple-half-block">
            <div class="row">
                {if $elements}
                    {set $rows = json_decode($elements, true)}
                    {foreach $rows as $row}
                        <!-- item -->
                        <div class="col-md-6">
                            {$row.text}
                            {if $row.image}
                                <img src="assets/files/{$row.image}" alt="{$row.title}">
                            {/if}
                        </div>
                        <!-- / item -->
                    {/foreach}
                {/if}
            </div>
        </div>
        {if $text}
            <div class="desc">{$text}</div>
        {/if}
    </div>
</section>

Блок отзывов (имя: reviewBlockTpl, описание: Блок отзывов):

<!-- SECTION REVIEWs -->
<section class="def-section reviews {$class}" id="section_{$MIGX_id}">
    <div class="container">
        <h2>{$title}</h2>
        {if $subtitle}
            <div class="desc">{$subtitle}</div>
        {/if}
        <div class="items">
            <div class="row">
                {if $elements}
                    {set $rows = json_decode($elements, true)}
                    {foreach $rows as $row}
                        <!-- item -->
                        <div class="col-md-4 col-sm-6">
                            <div class="item">
                                <div class="image">
                                    {set $image = $_modx->runSnippet("phpthumbon",[
                                        "input" => "assets/files/"~$row.image,
                                        "options" => "w=297&h=297&zc=1&q=99"
                                    ])}
                                    <img src="{$image}" alt="{$row.title}">
                                </div>
                                <div class="text">
                                    <span class="name">{$row.title}</span>
                                    {$row.text}
                                </div>
                            </div>
                        </div>
                        <!-- / item -->
                    {/foreach}
                {/if}
            </div>
        </div>
        {if $text}
            <div class="desc">{$text}</div>
        {/if}
    </div>
</section>
<!-- / SECTION REVIEWs -->

Блок формы (имя: formBlockTpl, описание: Форма на черном фоне):

<!-- FORM BLOCK -->
<div class="form-block" id="section_{$MIGX_id}">
    <div class="container">
        {$_modx->runSnippet("!AjaxForm", [
    		'snippet' => 'FormIt',
    		'form' => '@FILE chunks/form_text.tpl',
    		'hooks' => 'spam,email,FormItSaveForm',
    		'emailTpl' => '@FILE chunks/email_email.tpl',
    		'emailSubject' => 'Заявка с внутренних блоков',
    		'emailTo' => $_modx->getPlaceholder('+conf_to_email'),
    		'emailFrom' => $_modx->config.emailsender,
    		'formName' => 'Заявка с внутренних блоков',
    		'validate' => 'page:required,name:required,phone:required,username:blank',
    		'anchor' => $anchor
    	])}
    </div>
</div>
<!-- / FORM BLOCK -->

Блок аккордеон (имя: faqBlockTpl, описание: Блок аккордеон):

<!-- SECTION REVIEWs -->
<section class="def-section faq {$class}" id="section_{$MIGX_id}">
    <div class="container">
        <h2>{$title}</h2>
        {if $subtitle}
            <div class="desc">{$subtitle}</div>
        {/if}
        <div id="accordion" class="accordeon">
            {if $elements}
                {set $rows = json_decode($elements, true)}
                {foreach $rows as $row index=$index}
                    <div class="card">
                        <div class="card-header" id="heading{$index}">
                            <h5 class="mb-0">
                                <button class="btn btn-link" data-toggle="collapse" data-target="#collapse{$index}" aria-expanded="true" aria-controls="collapse{$index}">
                                  {$row.title}
                                </button>
                            </h5>
                        </div>

                        <div id="collapse{$index}" class="collapse {if $index==0}show{/if}" aria-labelledby="heading{$index}" data-parent="#accordion">
                            <div class="card-body">
                                {$row.text}
                            </div>
                        </div>
                    </div>
                {/foreach}
            {/if}
        </div>
        {if $text}
            <div class="desc">{$text}</div>
        {/if}
    </div>
</section>
<!-- / SECTION REVIEWs -->

Нам осталось вызвать все это дело корректно в шаблоне текстовой страницы:

{extends 'file:templates/index.tpl'}
{block 'content'}
    {if $_modx->resource.firstblock == 1}
        <div class="title-block mb-5">
            <div class="main-slider owl-carousel">
                {set $rows = json_decode($_modx->resource.slider_firstblock, true)}
                {foreach $rows as $key => $row}
                    {set $image = $_modx->runSnippet("phpthumbon", [
                        "input" => "assets/files/"~$row.image,
                        "options" => "w=1920&h=800&zc=1&q=99"
                    ])}
                    <div class="item" style="background: url({$image}) no-repeat;">
        
                    </div>
                {/foreach}
            </div>
            <div class="caption">
                <div class="container">
                    <h1>{$_modx->resource.longtitle ?: $_modx->resource.pagetitle}</h1>
        			{$_modx->runSnippet("!AjaxForm", [
        				'snippet' => 'FormIt',
        				'form' => '@FILE chunks/form_screen.tpl',
        				'hooks' => 'spam,email,FormItSaveForm',
        				'emailTpl' => '@FILE chunks/email_email.tpl',
        				'emailSubject' => 'Заявка с первого экрана',
        				'emailTo' => $_modx->getPlaceholder('+conf_to_email'),
        				'emailFrom' => $_modx->config.emailsender,
        				'formName' => 'Заявка с первого экрана',
        				'validate' => 'page:required,name:required,phone:required,username:blank',
        			])}
                </div>
            </div>
            <div class="bouncher">
                <a href="" class="bouncing-icon">'</a>
            </div>
        </div>
    {else}
        {include 'file:chunks/base_breadcrumbs.tpl'}
    {/if}
    {$_modx->runSnippet("@FILE snippets/get_sections.php", [
        "tvname" => "blocks"
    ])}
{/block}

Вот таким простым образом у нас получился конструктор страниц, который можно расширять. Самое главное он бесплатный и, по-моему, является хорошей альтернативой ContentBlocks.

MODX Revo ContentBlocks для бедных на основе MIGX

0 Число голосов: 8
5
5
1
8

Комментарии ()

  1. Паша Устюгов 06 мая 2020, 20:46 # 0
    очень полезное решение! благодарю!
    1. iEva01 14 мая 2020, 18:00 # 0
      Вот если бы это собрать еще как готовая приблуда для MIGX, качаемая из репозитория MODX… Было бы шикарно!
      1. Петропавловский Артем 15 мая 2020, 09:05 # 0
        Планируется переработка данного функционала в отдельный компонент. Возможно, платный.
      2. Vic 29 октября 2020, 09:56(Комментарий был изменён) # 0
        Приветствую! Работа проделана большая, но есть способ сделать это намного проще, через MIGX и Multiple Formtabs, вот инструкция modx.pro/howto/16558 вот как это выглядит в деле file.modx.pro/files/3/6/3/3639b7530cdb523c2c730f4df724a685.gif

        Наши клиенты

        Многие компании уже доверяют нам. Будьте в их числе!

        Хотите реализовать проект?

        Контакты

        Напишите нам - мы расскажем вам много интересного!


        Пермь, шоссе Космонавтов 252, офис 218