[СДЕЛАЙ САМ] Мультилендинг с помощью MIGX

Если вы не знаете, что такое MIGX вот список материалов для ознакомления
1. Статья с описанием основ
2. Видео с тем же самым, но от другого автора.
3. Статьи о других возможностях компонента Создание таблиц через MIGX и Создание CMP для вывода в админку с помощью MIGX
Для начала постараюсь описать результат того, что получится в итоге. Это будет некий примитивный конструктор страниц, т.е. дизайн должен быть сделан так, чтобы можно было без ущерба для внешнего вида менять местами блоки. Сами блоки или секции имеют постоянную структуру, что позволит сделать их контент редактируемым.

ДАННЫЙ ФУНКЦИОНАЛ ВНЕДРЁН В КОМПОНЕНТ MigxPageConfigurator

Дальше будет много букав, я предупредил.
Итак, поехали!

Первое что нужно сделать, это заготовки будущих секций, для этого:
1. Заходим Пакеты->MIGX
2. Переходим на вкладку MIGX
3. Жмём «Добавить элемент»
4. Заполняем поле name названием будущей секции, например sectionUtp.
5. Жмём «Выполнено»
6. Повторяем пункты 4 и 5 для всех секций.
7. Когда все секции созданы. Повторяем пункт 3, только заполняем поля как на скриншоте

8. Переходим на вкладку «Formtabs» и в поле Multiple Formtabs выбираем все секции созданные при выполнении пунктов 5 и 6.
9. В поле Multiple «Formtabs» Label указываем подпись. Должно получится как на картинке ниже

10. Под словом Fields жмём «Добавить элемент», в открывшемся окне ещё раз жмём «Добавить элемент».
11. Здесь указываем название поля (Fieldname), в котором будет храниться название секции, и подпись (Caption) к этому полю. Далее смотри п.5.

12. Если получилось как на скриншоте, жмем «Закрыть»

13. Переходим на кладку «Columns», выполняем п. 3
14. Заполняем заголовок(Header) и название поля(Field).!!! ВАЖНО!!! Field должно быть равно Fieldname из пункта 11. Повторяем п. 5. Сверяемся со скриншотом

15. Повторяем п. 12. И небольшое пояснение к проделанной работе, для тех кто не понял: мы только что создали конфигурацию для будущего TV типа migx, где «Formtabs»- вкладки формы, а «Columns» — разметка колонок. Больше информации о MIGX есть тут рекомендую почитать.

Это была самая простая часть. Продолжаем. Теперь нужно создать TV типа migx и прописать в Конфигурацию название только что созданной конфигурации, а так же указать название поля, подпись и шаблон, в котором данное TV будет доступно.




Теперь вернёмся к самим секциям. Пока они все пустые, давайте же их наполним. Я начту с той секции, которая у меня первая sectionUtp. смотрим пункты 1 и 2. Находим в списке нужную секцию, кликаем правой кнопкой и выбираем «Редактировать».
Вообще дальше всё очень индивидуально, поэтому я расскажу как делал сам, в качестве примера. В секции я создаю две вкладки: для настроек секции на тот случай, когда в какую-то отдельную секцию нужно добавить специальный класс, и для содержимого. Чтобы создать две вкладки, нужно перейти на вкладку «Formtabs» и «Добавить элемент».

Тут хочу обратить внимание на то, что только для текстовых полей необязательно указывать тип в поле input TV type. У меня в первой секции будут помимо текстовых полей, поле с картинкой (image) и поле migx, соответственно я указал для них нужные типы, а для поля типа migx ещё и название конфигурации в поле Configs

Но это не всё, для картинки нужно указать то, как это поле будет отрисовываться. Для этого переходим на вкладку «Columns», жмём «Добавить элемент» заполняем Header и Field, помним, что последнее должно быть равно Fieldname, и здесь де переходим на вкладку Rendrer, для картинки выбираем this.renderImage в поле Rendrer.

Теперь создадим конфигурацию для поля типа migx, я её назвал service, и в ней будут следующие поля
1. Иконка — icon
2. Название — name
3. ID — id
Конфигурацию создаём как и в самом начале, главное назвать так же, как написали в поле Configs.
В итоге всех этих манипуляций у ресурса с шаблоном Текстовый на вкладке Дополнительные поля будет примерно такая картина

Если нажмём на кнопку «Добавить секцию», увидим следующее

Если вам, как и мне не нравится, что в списке все секции имею непрезентабельные названия и вы хотите чтобы они были на русском, то выполняем пункты 1 и 2, находим нужную секцию, открываем на редактирование, переходим на вкладку «Formtabs», листаем вниз до поля Multiple Formtabs Optionstext, где вписываем русское название и нажимаем «Выполнено».
И тут кто-то спросит «вот так вот каждую секцию заполнять? а нельзя ли как-то скопировать, чтобы те же настройки секции каждый раз не создавать?». На что самые внимательные ответят «Конечно можно!»
Для того чтобы скопировать конфигурацию секции, кликаем по ней правой кнопкой, находим пункт «Экспорт/Импорт», копируем всё его содержимое. Затем вызываем контекстное меню уже на пустой секции, находим тот же пункт и вставляем, после чего можно эту секцию отредактировать: лишнее убрать, недостающее добавить.

!!! ВАЖНО!!! Данный способ вывода является неэффективным, смотри обновление от 07.08.2021
Самое интересное, как это всё вывести на странице. Сразу скажу, вам понадобится fenom
{set $config = $_modx->resource.config | fromJSON}
{foreach $config as $key => $section}
    {if $section['bg_img']}
        {set $mainBg = $section['bg_img'] | pThumb: 'w=1920&h=1080&zc=1&q=60&f=png'}
    {/if}

    {switch $section['MIGX_formname']}
        {case 'sectionUtp'}
            {set $chunk = '@FILE chunks/sections/utp.html'}

        {case 'sectionFeatures'}
            {set $chunk = '@FILE chunks/sections/features.html'}
    {/switch}
    
    <section class="{$section['classes']}" id="{$section['id']}" style="background-image: url('{$mainBg}')">
          {$_modx->parseChunk($chunk, $section)}
    </section>   

{/foreach}
!!! ВАЖНО!!! Данный способ вывода является неэффективным, смотри обновление от 07.08.2021
Данный кейс можно использовать для А/В тестирования лендингов, задав в настройках секции ещё одно поле, например utm, в которое записывать метки для которых будет показан этот блок. тогда код шаблона будет такой
{set $config = $_modx->resource.config | fromJSON}
{set $allUTMs = $_modx->config.all_utms | split: ','} <!-- создаем системную настройку со всеми возможными метками -->
{foreach $config as $key => $section}
    {if $section['bg_img']}
        {set $mainBg = $section['bg_img'] | pThumb: 'w=1920&h=1080&zc=1&q=60&f=png'}
    {/if}

    {switch $section['MIGX_formname']}
        {case 'sectionUtp'}
            {set $chunk = '@FILE chunks/sections/utp.html'}

        {case 'sectionFeatures'}
            {set $chunk = '@FILE chunks/sections/features.html'}
    {/switch}
    
    {set $utms = $section['utm'] | split : ','}

    {set $rawUTM = $.get['utm_campaign'] | split: '|'}
    {set $currentUTM = $rawUTM[1] ?: $.get['utm_campaign']}

    {if !($currentUTM in list $allUTMs) && (1 in list $utms)}
        {set $allow = true}
    {elseif $currentUTM in list $allUTMs}
        {if $currentUTM in list $utms}
            {set $allow = true}
        {else}
            {set $allow = false}
        {/if}
    {else}
        {set $allow = false}
    {/if}

    {if $allow == true}
        <section class="{$section['MIGX_id']} {$paddings} {$section['classes']}" id="{$section['id'] | ereplace: '/[^a-zA-Z]/' : ''}" {$mainBg}>
            {$_modx->parseChunk($chunk, $section)}
        </section>

        {if $section['MIGX_formname'] == 'sectionFAQ'}
            {set $sectionFAQ = 1}
        {/if}
        {set $order = $order + 1}

    {/if}

{/foreach}
!!! ВАЖНО!!! Если на одной странице вам нужно использовать два блока одинакового типа их id должны быть разными даже в том случае, если они у вас не будут показаны одновременно. Например, вы хотите показывать разные офферы при переходе по разным объявлениям, создаете два блока типа Оффер с разным наполнением и вот у них должны быть разные id, иначе при обновлении страницы ресурса в админке один из них будет удаляться.

UPD от 02.02.21
Информация для тех кто разобрался.
Я тут подумал, что слишком много однообразных действий и надо бы немного автоматизировать процесс. Для этого
1.Качаем файл с дефолтным конфигом, он содержит
Для вкладки «Настройки секции» поля:
id — text
section_name — text
classes — text
section_img — image
atributes — text
Для вкладки «Содержимое секции»
header — texearea
subheader — textearea
btn_text — text
content — richtext
2. Кому совсем лень может скачать файл с настройками конфигурации config
3. Все секции нужно поместить в одну папку и назвать как-нибудь понятно.
4. Запустить в Console вот такой скрипт, указав путь к папке с секциями.
<?php
// подключаем модель объекта MIGX
$modx->addPackage('migx', $modx->getOption('core_path').'components/migx/model/');

// указываем имя созданной вручную или импортированной из файла конфигурации, из которой будет брать настройки
$defaultSectionName = 'sectionAbout';

// получаем базовые настройки секции
$defaultConfig = $modx->getObject('migxConfig', array('name' => $defaultSectionName));
$defaultConfig = $defaultConfig->toArray();
unset($defaultConfig['id']); // удаляем id, т.к. он задается автоматически при создании объекта

// указываем путь к папке с шаблонами секций, предполагается что это файлы .html
$sectionsPath = MODX_BASE_PATH . 'core/templates/chunks/sections/';
// собираем все имена файлов в массив
$fileNames = scandir($sectionsPath);
unset($fileNames[0],$fileNames[1]); // удаляем ненужные нам элементы массива, которые возвращает функция scandir()

// подготавливаем и выполняем запрос в БД, чтобы получить имена уже созданных конфигураций.
$sql = 'SELECT name FROM '.$modx->getOption('table_prefix').'migx_configs';
$statement = $modx->query($sql);
$configNames = $statement->fetchAll(PDO::FETCH_COLUMN);

foreach($fileNames as $name){
 	$name = preg_replace('/\..*$/','', $name); // вырезаем расширение из имени
 	$defaultConfig['name'] = $name;
 	$defaultConfig['extended']['multiple_formtabs_optionstext'] = str_replace('section','', $name); // формируем подпись для списка конфигураций
 	if(!in_array($name, $configNames)){ // если такой конфигурации нет, то создаем новый объект
 		$defaultConfig['createdon'] = date('Y-m-d H:i:s');
 		$newConfig = $modx->newObject('migxConfig');
 		
 	}
 	else{ // или получаем конфигурацию из БД для обновления
 		$newConfig = $modx->getObject('migxConfig', array('name' => $name));
 		$defaultConfig['editedon'] = date('Y-m-d H:i:s');
 	}
 	$newConfig->fromArray($defaultConfig);
 	$newConfig->save(); 	
 }
Этим же скриптом можно обновлять общие настройки.

!!! ВАЖНО!!! Данный способ вывода является неэффективным, смотри обновление от 07.08.2021
Есть ещё нюанс, если мы создаем секции с помощью этого скрипта, то цикл который выводит их на фронте можно сделать проще, без switcch, нам надо только подставлять в имя чанка имя секции из поля MIGX_formname.
{set $config = $_modx->resource.config | fromJSON}

{foreach $config as $key => $section}
    {set $mainBg = ''}
    {if $section['section_img']}
        {set $mainBg = $section['section_img'] | pThumb: 'w=1920&h=1080&zc=1&q=60&f=webp&bg=transparent'}
        {set $mainBg = 'style="background-image: url('~$mainBg~')"'}
    {/if}

    {set $chunk = '@FILE chunks/sections/'~$section['MIGX_formname']~'.html'}

    <!-- 
    добавляем в массив параметров секции поля ресурса и конфигурации, чтобы не делать лишних запросов
    естественно это по желанию и необходимости.
     -->
    {set $section['pagetitle'] = $pagetitle}
    {set $section['longtitle'] = $longtitle}
    {set $section['menutitle'] = $menutitle}
    {set $section['description'] = $description}
    {set $section['introtext'] = $introtext}
    {set $section['content'] = $content}
    {set $section['id'] = $id}
    {set $section['phone'] = $phone}
    {set $section['email'] = $email}
    {set $section['address'] = $address}
    {set $section['phoneFormatted'] = $phoneFormatted}


    <section class="{$section['classes']}" id="{$section['id']}" {$section['attributes']} {$mainBg}>
        {$_modx->parseChunk($chunk, $section)}
    </section>

{/foreach}

UPD от 07.08.21
Поскольку старшие товарищи сказали, что всю сложную логику из шаблонов надо убирать и потому, что скорость отдачи сервером страницы с конфигуратором была ниже желаемой, мной было принято решение написать плагин для того, чтобы парсить html на этапе сохранения ресурса. Для этого я создал TV типа Текстовая область(textarea) с именем parsed_config, куда буду сохранять частично распарсенную конфигурацию страницы. Почему частично? Ну потому, что некоторая логика, а так же сниппеты должны парситься при запросе с фронта. Для частичного парсинга пришлось немного изменить шаблоны секций, те участки кода, которые должны парситься при запросе с фронта были обёрнуты в
##code}

Вот пример одной секции
{if $bg_img} <!-- это распарсится в плагине -->
    ##set $mainBg = '{$bg_img}' | pThumb: 'w=1920&h=1080&zc=1&q=60&f=webp&bg=transparent'} <!-- а это на фронте -->
    ##set $mainBg = 'style="background-image: url('~$mainBg~')"'}
    {/if}
    <!-- это пример того как можно обрабатывать utm-метки -->
    ##set $currentUTM = $.get['utm'] ?: 1}
    ##if !('{$utm}') || ($currentUTM in list [{$utm}])}
    ##set $bool = true}
    ##else}
    ##set $bool = false}
    ##/if}

    ##if $bool}
    <section class="{$paddings} {$classes}" id="{$id | ereplace: '/[^a-zA-Z]/' : ''}"  ##$mainBg}>
        <!-- КВИЗ -->
        <div class="container lines lines-close">
            <div class="row justify-content-center">
                {$header}
                {$sub_header}
            </div>
            ##'!AjaxForm' | snippet : [
            'form' => '@FILE chunks/forms/quizForm.html',
            'snippet' => 'FormIt',
            'hooks' => 'FormItSaveForm,sendTelegram,sendFormByEmail',
            'emailSubject' => 'Результат опроса',
            'emailTo' => '{$_modx->config.email}',
            'emailFrom' => 'noreply@'~'{$_modx->config.http_host}',
            'emailTpl' => '@FILE chunks/emails/tplEmailQuiz.html',
            'validate' => 'phone:required:regexp=/^\+7\(\d##3}\)\d##3}-\d##2}-\d##2}$/,secret:contains=^'~'{$_modx->config.secret}'~'^',
            'validationErrorMessage' => 'В форме содержатся ошибки!',
            'successMessage' => '{$notify}',
            'formname' => 'Квиз',
            'quiz' => '{($quiz | toJSON) | replace: '{': '{ '}' // потому что в параметре массив не передается  в том виде, в котором он приходит с сервера
            ]}
        </div>
        <!-- /КВИЗ -->
    </section>
    ##/if}

И я написал плагин на событие OnDocFormSave, который частично парсит конфигурацию и сохраняет её в TV parsed_config
<?php
if($resource->getTVValue('config')){
    $sections = json_decode($resource->getTVValue('config'), 1);
    $pdoTools = $modx->getService('pdoTools');
    $html = '';
    foreach($sections as $key => $section){
        $section['resource_id'] = $id;
        foreach($section as $key => $value){
            if(strpos($value, '[{') !== false){
                $section[$key] = json_decode($value,1); // преобразуем поля типа migx в массив               
            }
        } 
        $chunkName = str_replace('section', '', $section['MIGX_formname']); // это если файл секции называется utp.html, а сама секция sectionUtp, иначе эту строчку надо удалить.
        $chunk = '@FILE chunks/sections/'.strtolower($chunkName).'.html';       
        $tmp = $pdoTools->parseChunk($chunk, $section);
        $html .= str_replace('##', '{', $tmp); // чтобы на фронте работал парсер pdoTools
    }   
    $resource->setTVValue('parsed_config', $html);
    $resource->save();
}
На этом у меня всё. Надеюсь эта информация кому-нибудь пригодится.
На все вопросы отвечу в комментариях. если они будут.
Артур Шевченко
28 января 2021, 18:18
modx.pro
4
1 821
+9
Поблагодарить автора Отправить деньги

Комментарии: 0

Авторизуйтесь или зарегистрируйтесь, чтобы оставлять комментарии.
0