03 марта 2026, 09:49 А теперь все эту красоту оформляем в виде сниппета. Параметры по-умолчанию редактируем в самом сниппете elements/snippets/bgImage.php <?php /** * Сниппет bgImage — обработка изображений через phpThumbOn * * Параметры: * - image (обязательный) — путь к исходному изображению * - width (опционально) — ширина итогового изображения (по умолчанию 600) * - height (опционально) — высота итогового изображения (по умолчанию 300) * - quality (опционально) — качество сжатия (по умолчанию 100) * - blur_strength (опционально) — сила размытия для фона (по умолчанию 9) * - brightness (опционально) — яркость для фона (по умолчанию 15) * - watermark_opacity (опционально) — прозрачность водяного знака (по умолчанию 100) */ // Получаем параметры $image = $modx->getOption('image', $scriptProperties, ''); $width = $modx->getOption('width', $scriptProperties, 600); $height = $modx->getOption('height', $scriptProperties, 300); $quality = $modx->getOption('quality', $scriptProperties, 100); $blur = $modx->getOption('blur_strength', $scriptProperties, 9); $brightness = $modx->getOption('brightness', $scriptProperties, 15); $watermarkOpacity = $modx->getOption('watermark_opacity', $scriptProperties, 100); // Проверяем, что изображение передано if (empty($image)) { $modx->log(modX::LOG_LEVEL_ERROR, 'ProcessImage: не передан параметр image'); return ''; } // Шаг 1. Уменьшение основного изображения без обрезки $mainImageParams = "w={$width}&h={$height}&zc=0&q={$quality}&aoe=1"; $processedImage = $modx->runSnippet('phpthumbon', [ 'input' => $image, 'options' => $mainImageParams ]); // Шаг 2. Создание фонового изображения с размытием и яркостью // Применяем 9 фильтров размытия для усиления эффекта $blurFilters = ''; for ($i = 0; $i < 9; $i++) { $blurFilters .= "fltr[]=blur|{$blurStrength}&"; } $bgImageParams = "w={$width}&h={$height}&zc=1&{$blurFilters}fltr[]=brit|{$brightness}"; $bgImage = $modx->runSnippet('phpthumbon', [ 'input' => $image, 'options' => $bgImageParams ]); // Шаг 3. Создание водяного знака из основного изображения // Используем обработанное основное изображение как водяной знак $filter = "fltr[]=wmi|{$processedImage}|C|{$watermarkOpacity}"; // Шаг 4. Генерация финального изображения с фоном и водяным знаком $finalImage = $modx->runSnippet('phpthumbon', [ 'input' => $bgImage, 'options' => $filter ]); return $finalImage; ?> Вывод изображения на странице. Параметры можно опустить или указать под разные задачи {set $image = $_modx->runSnippet('@FILE snippets/bgImage.php', [ 'image' => $image, 'width' => 1200, 'height' => 675, 'brightness' => 5, 'blurStrength' => 20 ])} <img src="{$image}"> Вопросы / Унифицированное отображение разноформатных изображений без обрезки (решено) 1 +2
21 февраля 2026, 01:40 Далее код оставил без изменений <script type="text/javascript"> // <![CDATA[ {literal} Ext.onReady(function () { var fld = MODx.load({ {/literal} xtype: 'textfield', applyTo: 'tv{$tv->id}', width: '99%', id: 'tv{$tv->id}', enableKeyEvents: true, allowBlank: {if $params.allowBlank == 1 || $params.allowBlank == 'true'}true{else}false{/if}, value: '{$tv->value}', {literal} listeners: {'change': {fn: MODx.fireResourceFormChange, scope: this}}, }); Ext.getCmp('modx-panel-resource').getForm().add(fld); MODx.makeDroppable(fld); }); {/literal} // ]]> </script> {$fields = [ 'title' => $_config.videogallery_field_title, 'desc' => $_config.videogallery_field_desc, 'image' => $_config.videogallery_field_image, 'video' => $_config.videogallery_field_video, 'videoId' => $_config.videogallery_field_videoId, 'videoDuration' => $_config.videogallery_field_videoDuration ]} {foreach from=$fields key=name item=item} {if $item != ''} {if substr($item, 0,3) == 'tv.'} {$vg_fields[$name] = str_replace('tv.', '', $item)} {$input_ids_data = "tv`$modx->getObject('modTemplateVar', ['name'=>$vg_fields[$name]] )->id`"} {if $input_ids_data != 'tv' AND $input_ids_data != ''} {$input_ids[$name] = $input_ids_data} {/if} {else} {$vg_fields[$name] = $item} {$input_ids[$name] = "modx-resource-`$vg_fields[$name]`"} {/if} {/if} {/foreach} <script type="text/javascript"> // <![CDATA[ Ext.onReady(function () { if (typeof vgHandlers == 'undefined') { vgHandlers = { /* */ }; } vgHandlers['{$tv->id}'] = new videoGalleryHandler({ tv: '{$tv->id}', tvid: '{$tvid}', resource: {$modx->resource->id}, actionUrl: MODx.config.assets_url + 'components/videogallery/connector.php?HTTP_MODAUTH=' + MODx.siteId + '&wctx=mgr&action=mgr/gallery/handle', selectors: { tvInput: '#tv{$tv->id}', }, callbacks: { success: function (resp) { var element = { /* */ }; element['{$tv->id}'] = { /* */ }; {foreach from=$fields key=name item=field} {if $field != '' AND $field != 'tv'} if (resp.object.hasOwnProperty('{$name}')) { element['{$tv->id}']['{$name}'] = document.querySelector('#{$input_ids[$name]}'); if (element['{$tv->id}']['{$name}']) { element['{$tv->id}']['{$name}'].value = resp.object['{$name}']; } } {/if} {/foreach} }, reset: function () { var element = { /* */ }; element['{$tv->id}'] = { /* */ }; {foreach from=$fields key=name item=field} {if $field != '' AND $field != 'tv'} element['{$tv->id}']['{$name}'] = document.querySelector('#{$input_ids[$name]}'); if (element['{$tv->id}']['{$name}']) { element['{$tv->id}']['{$name}'].value = ''; } {/if} {/foreach} }, }, }); }); // ]]> </script> {* Fix "Smarty Compiler: Syntax error {/foreach} unclosed {foreach} tag" *} {foreach from=$fields key=name item=field} {/foreach} Вопросы / Помогите добить VideoGallery 2 0
21 февраля 2026, 01:38 Функция сохранения <script type="text/javascript"> // <![CDATA[ Ext.onReady(function () { // Сохраняем исходные значения при загрузке const originalValues = { title: document.getElementById('vgTitle_{$tv->id}').value, desc: document.getElementById('vgDesc_{$tv->id}').value, video: document.getElementById('vgVideo_{$tv->id}').value, videoId: document.getElementById('vgVideoId_{$tv->id}').value, image: document.getElementById('vgImage_{$tv->id}').value, videoDuration: document.getElementById('vgVideoDuration_{$tv->id}').value }; window.compareAndSave = function(tvId) { const currentValues = { title: document.getElementById('vgTitle_' + tvId).value, desc: document.getElementById('vgDesc_' + tvId).value, video: document.getElementById('vgVideo_' + tvId).value, videoId: document.getElementById('vgVideoId_' + tvId).value, image: document.getElementById('vgImage_' + tvId).value, videoDuration: document.getElementById('vgVideoDuration_' + tvId).value }; // Проверяем, есть ли изменения let hasChanges = false; for (const key in currentValues) { if (currentValues[key] !== originalValues[key]) { hasChanges = true; break; } } if (!hasChanges) { alert('Нет изменений для сохранения.'); return; } // Формируем новый JSON const newJson = JSON.stringify(currentValues); // Обновляем скрытое поле document.getElementById('tv' + tvId).value = newJson; // Сигнализируем MODX об изменении if (typeof MODx !== 'undefined' && MODx.fireResourceFormChange) { MODx.fireResourceFormChange(); } alert('Данные сохранены!'); // Обновляем исходные значения (чтобы следующие изменения сравнивались корректно) Object.assign(originalValues, currentValues); }; // Интеграция с videoGalleryHandler if (typeof vgHandlers !== 'undefined' && vgHandlers['{$tv->id}']) { vgHandlers['{$tv->id}'].callbacks.success = function(resp) { // Обновляем поля формы document.getElementById('vgVideo_{$tv->id}').value = resp.object.video || ''; document.getElementById('vgVideoId_{$tv->id}').value = resp.object.videoId || ''; document.getElementById('vgImage_{$tv->id}').value = resp.object.image || ''; }; } }); // ]]> </script> <style> .videogallery-wrapper { padding:10px; border:1px solid #ddd; border-radius:4px; } .videogallery-fields div { margin:10px 0; } label { display:inline-block; width:120px; font-weight:bold; } input,textarea { width:100%; padding:5px; box-sizing:border-box; } </style> Вопросы / Помогите добить VideoGallery 2 0
09 февраля 2026, 20:43 А вот все то же самое, только на fenom сразу вызов на странице без дополнительных чанков {set $rows = $.php.array_reverse(json_decode($_modx->resource.videogallery, true))} {if $rows && is_array($rows)} <!-- Табы (заголовки) --> <ul class="nav nav-tabs" id="videoTab" role="tablist"> {foreach $rows as $idx => $row} <li class="nav-item" role="presentation"> <button class="nav-link {if $idx == 0}active{/if}" id="videogal-tab-{$idx}" data-bs-toggle="tab" data-bs-target="#videogal{$idx}" type="button" role="tab" aria-controls="videogal{$idx}" aria-selected="{if $idx == 0}true{else}false{/if}"> Источник {$idx + 1} </button> </li> {/foreach} </ul> <!-- Контент табов --> <div class="tab-content" id="videoTabContent"> {foreach $rows as $idx => $row} {* Декодируем JSON из поля video *} {set $videoData = json_decode(trim($row.video, '"') | replace:'\"':'"', true)} {if $videoData} <div class="tab-pane fade {if $idx == 0}show active{/if}" id="videogal{$idx}" role="tabpanel" aria-labelledby="videogal-tab-{$idx}"> <!-- Видео --> <div class="pb-3"> <div class="embed-responsive embed-responsive-16by9" style="width: 100%;"> <iframe class="embed-responsive-item" src="{$videoData.video}" title="{$videoData.title | default:'Видео'}" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" webkitAllowFullScreen mozallowfullscreen allowFullScreen allowtransparency="true" name="main" style="width:100%; height:100%; background-image:url({$videoData.image | default:''}); background-size: cover; background-repeat: no-repeat; background-position: center center;"></iframe> </div> </div> <!-- Ссылка на источник --> <div class="pb-3"> Видео в источнике: <ignore><a href="{$videoData.video}" target="_blank">{$videoData.video}</a></ignore> </div> <!-- Описание (если есть) --> {if isset($videoData.desc) && $videoData.desc} <div class="pb-3">{$videoData.desc | nl2br}</div> {/if} </div> {else} <!-- Резервный блок при ошибке декодирования --> <div class="tab-pane fade {if $idx == 0}show active{/if}" id="videogal{$idx}" role="tabpanel" aria-labelledby="videogal-tab-{$idx}"> <p class="text-danger">Не удалось загрузить видео (ошибка JSON).</p> </div> {/if} {/foreach} </div> {else} <p>Нет данных для отображения.</p> {/if} Готовые решения / Видеогалерея на MIGX. Может кому понадобится (решено) 3 +1
09 февраля 2026, 15:03 решение в итоге нашлось? Вопросы / Как сделать, чтобы getImageList понимал тэги Fenom? 1 0
09 февраля 2026, 14:09 у меня заработала только эта конструкция. пробелы вокруг условия и двойные кавычки &sort =`[{ "sortby":"MIGX_id", "sortdir":"DESC" }]` Вопросы / pdoPage и getImageList сортировка 12 0
09 февраля 2026, 13:37 Переносим все видео ранее созданные на сайте с tv-полями video =1 и video2 = 26 в новое tv-поле videogallery = 38 -- Шаг 1: увеличиваем лимит для текущей сессии SET SESSION group_concat_max_len = 1000000; -- Шаг 2: выполняем основной запрос INSERT INTO modx_site_tmplvar_contentvalues (tmplvarid, contentid, value) SELECT 38 AS tmplvarid, src.contentid, CONCAT( '[', GROUP_CONCAT( CONCAT( '{', '"MIGX_id":"', src.migx_num, '",', '"video":"', REPLACE( REPLACE( REPLACE(src.value, '\\', '\\\\'), '"', '\\"' ), '\n', '\\n' ), '"}' ) ORDER BY src.migx_num SEPARATOR ',' ), ']' ) AS value FROM ( SELECT t1.contentid, t1.value, 1 AS migx_num FROM modx_site_tmplvar_contentvalues t1 WHERE tmplvarid = 1 UNION ALL SELECT t26.contentid, t26.value, 2 AS migx_num FROM modx_site_tmplvar_contentvalues t26 WHERE tmplvarid = 26 ) AS src GROUP BY src.contentid ON DUPLICATE KEY UPDATE value = VALUES(value); Готовые решения / Видеогалерея на MIGX. Может кому понадобится (решено) 3 0
09 февраля 2026, 10:47 Для вывода данной migx videogallery в виде табов Источник1, Источник2 и тд Чанк videogalleryVideosTabs.tpl [[!VideoJsonToPlaceholders? &json=`[[+video]]` &prefix=`video[[+idx]].`]] <li class="nav-item" role="videocase"> <button class="nav-link [[+idx:isequal=`1`:then=`active`:else=``]]" id="videogal[[+idx]]-tab" data-bs-toggle="tab" data-bs-target="#videogal[[+idx]]" type="button" role="tab" aria-controls="videogal[[+idx]]" aria-selected="true">Источник [[+idx]]</button> </li>` Чанк videogalleryVideos.tpl <div class="tab-pane fade [[+idx:isequal=`1`:then=`show active`:else=``]]" id="videogal[[+idx]]" role="tabpanel" aria-labelledby="videogal[[+idx]]-tab"> <div class="pb-3"> <div class="embed-responsive embed-responsive-16by9" style="width: 100%;"> <iframe class="embed-responsive-item" src="[[+video[[+idx]].video]]" title="[[+video[[+idx]].title]]" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" webkitAllowFullScreen mozallowfullscreen allowFullScreen allowtransparency="true" name="main" style="width:100%;height:100%;background-image:url([[+video[[+idx]].image]]);background-size: cover; background-repeat: no-repeat;background-position: center center;"> </iframe> </div> </div> <div class="pb-3">видео в источнике <ignore><a href="[[+video[[+idx]].video]]" target="_blank">[[+video[[+idx]].video]]</a></ignore></div> </div> Вызов на странице <ul class="nav nav-tabs" id="videoTab" role="tablist"> [[!getImageList? &tvname=`videogallery` &tpl=`videogalleryVideosTabs.tpl` ]] </ul> <div class="tab-content" id="videoTabContent"> {'!getImageList' | snippet : [ 'tvname' => 'videogallery', 'tpl' => 'videogalleryVideos.tpl']} </div> Готовые решения / Видеогалерея на MIGX. Может кому понадобится (решено) 3 0
09 февраля 2026, 01:44 решал эту проблему следующим образом установил autoRedirector далее через phpMyAdmin экспортировал со старого сайта modx_site_content залил в базу к новому с именем modx_site_content_old сравнил две базы. если у одинаковых id ресурсов значения uri не совпадают, то добавил новые редиректы в базу modx_ar_rules удалил дубликаты записей в modx_ar_rules удалил modx_site_content_oldINSERT INTO `modx_ar_rules` (`res_id`, `context_key`, `uri`) SELECT sc.id AS res_id, 'web' AS context_key, sc2.uri AS uri FROM modx_site_content sc LEFT JOIN modx_site_content_old sc2 ON sc.id = sc2.id WHERE sc.uri <> sc2.uri; -- uri не совпадают DELETE FROM `modx_ar_rules` WHERE id NOT IN ( SELECT `min_id` FROM ( SELECT MIN(id) AS min_id FROM modx_ar_rules GROUP BY `res_id`, `context_key`, `uri` ) AS keep );все четенько на 7К ресурсов в несколько кликов Вопросы / Как массово добавить 301 редиректы? 6 0
29 января 2026, 11:29 код для генерации схем MIGXdb может кому пригодится или доработается <!DOCTYPE html> <html lang="ru"> <head> <meta charset="UTF-8"> <title>XML Generator for MIGX (Table View)</title> <style> body { font-family: Arial, sans-serif; margin: 20px; color: #333; } .config-group { margin-bottom: 20px; padding: 15px; border: 1px solid #ddd; border-radius: 6px; background-color: #f9f9f9; } .config-group label { display: block; margin: 8px 0 4px; font-weight: bold; font-size: 0.9em; } .config-group input { width: 100%; padding: 8px; border: 1px solid #ccc; border-radius: 4px; box-sizing: border-box; } .mjg_input_rows { width: 100%; border-collapse: collapse; margin-bottom: 20px; } .mjg_input_rows th { background-color: #f2f2f2; text-align: left; padding: 12px; font-weight: bold; border: 1px solid #ddd; } .mjg_input_rows td { padding: 10px; border: 1px solid #ddd; vertical-align: top; } .mjg_input_field input, .mjg_input_caption input, .mjg_input_inputTVtype select { width: 100%; padding: 8px; border: 1px solid #ccc; border-radius: 4px; box-sizing: border-box; } .mjg_input_showintabs label, .mjg_input_sortable label { display: flex; align-items: center; gap: 5px; } .mjg_input_deleterow_action { color: #dc3545; cursor: pointer; font-weight: bold; } .mjg_input_rows_add_wr { margin: 15px 0; } .mjg_input_rows_add { display: inline-block; background: #28a745; color: white; padding: 10px 15px; border-radius: 4px; cursor: pointer; font-size: 0.9em; } .mjg_input_rows_add:hover { background: #218838; } textarea { width: 100%; height: 300px; font-family: monospace; padding: 12px; border: 1px solid #ccc; border-radius: 4px; resize: vertical; box-sizing: border-box; margin-top: 10px; font-size: 0.95em; } h1 { color: #2c3e50; margin-bottom: 20px; } /* Стили для выпадающего списка опций (скрыт по умолчанию) */ .mjg_input_inputTVtype_inputOptionValues { margin-top: 8px; display: none; } .mjg_input_inputTVtype_inputOptionValues_item { display: flex; gap: 8px; margin-bottom: 5px; } .mjg_input_inputTVtype_inputOptionValues_item input { flex: 1; padding: 6px; } .mjg_input_inputTVtype_inputOptionValues_item_delete { color: #dc3545; cursor: pointer; font-weight: bold; } .mjg_input_inputTVtype_inputOptionValues_add { color: #007bff; cursor: pointer; font-size: 0.85em; margin-top: 5px; } </style> </head> <body> <h1>Генератор XML для MIGX/MODX (Таблица)</h1> <!-- Основные настройки модели --> <div class="config-group"> <label for="modelPackage">Package (model package)</label> <input type="text" id="modelPackage" value="mygallery" placeholder="Например: mygallery"> <label for="objectClass">Class (object class)</label> <input type="text" id="objectClass" value="myGallery" placeholder="Например: myGallery"> <label for="tableName">Table (table)</label> <input type="text" id="tableName" value="migx_gallery" placeholder="Например: migx_gallery"> </div> <div class="mjg_input_rows"> <table> <thead> <tr> <th>Ключ (key) <span style="font-size:12px;color:#888;">Например: title</span></th> <th>Тип БД (dbtype) <span style="font-size:12px;color:#888;">varchar, int и др.</span></th> <th>Точность (precision) <span style="font-size:12px;color:#888;">Для varchar/int</span></th> <th>PHP-тип (phptype) <span style="font-size:12px;color:#888;">string, integer и др.</span></th> <th>NULL?</th> <th>Значение по умолчанию</th> <th>Индекс</th> <th></th> </tr> </thead> <tbody id="fieldsContainer"> <!-- Первая строка по умолчанию --> <tr class="mjg_input_row" id="field_1"> <td class="mjg_input_field"> <input type="text" name="key" placeholder="title" required> </td> <td class="mjg_input_dbtype"> <select name="dbtype" onchange="updatePhpType(this)"> <option value="varchar">varchar</option> <option value="text">text</option> <option value="int">int</option> <option value="datetime">datetime</option> <option value="tinyint">tinyint</option> <option value="json">json</option> </select> </td> <td class="mjg_input_precision"> <input type="text" name="precision" placeholder="255"> </td> <td class="mjg_input_phptype"> <select name="phptype" required> <option value="string">string</option> <option value="integer">integer</option> <option value="datetime">datetime</option> <option value="json">json</option> </select> </td> <td class="mjg_input_null"> <label><input type="checkbox" name="null" checked> Да</label> </td> <td class="mjg_input_default"> <input type="text" name="default" placeholder="0"> </td> <td class="mjg_input_index"> <select name="index"> <option value="">—</option> <option value="index">index</option> <option value="fulltext">fulltext</option> <option value="unique">unique</option> </select> </td> <td class="mjg_input_deleterow"> <span class="mjg_input_deleterow_action" onclick="removeField('field_1')">X</span> </td> </tr> </tbody> </table> <div class="mjg_input_rows_add_wr"> <div class="mjg_input_rows_add" onclick="addField()">Добавить строку</div> </div> </div> <!-- Кнопка генерации XML --> <div style="margin: 20px 0;"> <button type="button" onclick="generateXML()" style=" background: #007bff; color: white; border: none; padding: 10px 20px; border-radius: 4px; cursor: pointer; font-size: 1em; ">Сгенерировать XML</button> </div> <h2>Результат (XML)</h2> <textarea id="output" placeholder="Здесь появится сгенерированный XML..." readonly></textarea> <script> let fieldCount = 1; // Начинаем с 1, т.к. первая строка уже есть function addField() { fieldCount++; const container = document.getElementById('fieldsContainer'); const newRow = document.createElement('tr'); newRow.className = 'mjg_input_row'; newRow.id = `field_${fieldCount}`; newRow.innerHTML = ` <td class="mjg_input_field"> <input type="text" name="key" placeholder="title" required> </td> <td class="mjg_input_dbtype"> <select name="dbtype" onchange="updatePhpType(this)"> <option value="varchar">varchar</option> <option value="text">text</option> <option value="int">int</option> <option value="datetime">datetime</option> <option value="tinyint">tinyint</option> <option value="json">json</option> </select> </td> <td class="mjg_input_precision"> <input type="text" name="precision" placeholder="255"> </td> <td class="mjg_input_phptype"> <select name="phptype" required> <option value="string">string</option> <option value="integer">integer</option> <option value="datetime">datetime</option> <option value="json">json</option> </select> </td> <td class="mjg_input_null"> <label><input type="checkbox" name="null" checked> Да</label> </td> <td class="mjg_input_default"> <input type="text" name="default" placeholder="0"> </td> <td class="mjg_input_index"> <select name="index"> <option value="">—</option> <option value="index">index</option> <option value="fulltext">fulltext</option> <option value="unique">unique</option> </select> </td> <td class="mjg_input_deleterow"> <span class="mjg_input_deleterow_action" onclick="removeField('field_${fieldCount}')">X</span> </td>`; container.appendChild(newRow); } function removeField(id) { const el = document.getElementById(id); if (el) el.remove(); } function updatePhpType(selectEl) { const dbtype = selectEl.value; const row = selectEl.closest('tr'); const phptypeSelect = row.querySelector('select[name="phptype"]'); let suggestedType = 'string'; switch (dbtype) { case 'int': case 'tinyint': suggestedType = 'integer'; break; case 'datetime': suggestedType = 'datetime'; break; case 'json': suggestedType = 'json'; break; } phptypeSelect.value = suggestedType; } function escapeXml(str) { if (typeof str !== 'string') return ''; return str .replace(/&/g, '&') .replace(/</g, '<') .replace(/>/g, '>') .replace(/"/g, '"') .replace(/'/g, '''); } function generateXML() { // Получаем основные параметры const modelPackage = escapeXml(document.getElementById('modelPackage').value.trim() || 'mytable'); const objectClass = escapeXml(document.getElementById('objectClass').value.trim() || 'myTable'); const tableName = escapeXml(document.getElementById('tableName').value.trim() || 'migx_table'); const rows = document.querySelectorAll('#fieldsContainer tr.mjg_input_row'); const xmlLines = []; // Заголовок XML xmlLines.push('<?xml version="1.0" encoding="UTF-8"?>'); xmlLines.push(`<model package="${modelPackage}" baseClass="xPDOObject" platform="mysql" defaultEngine="MyISAM" version="1.1">`); xmlLines.push(` <object class="${objectClass}" table="${tableName}" extends="xPDOSimpleObject">`); // Обработка каждой строки таблицы rows.forEach(row => { const keyInput = row.querySelector('input[name="key"]'); const key = keyInput ? keyInput.value.trim() : ''; // Пропускаем строку, если ключ не указан if (!key) { console.warn('Пропущена строка без ключа:', row); return; } let fieldXml = ` <field key="${escapeXml(key)}"`; const dbtype = row.querySelector('select[name="dbtype"]').value; if (dbtype) fieldXml += ` dbtype="${escapeXml(dbtype)}"`; const precision = row.querySelector('input[name="precision"]').value.trim(); if (precision) fieldXml += ` precision="${escapeXml(precision)}"`; const phptype = row.querySelector('select[name="phptype"]').value; if (phptype) fieldXml += ` phptype="${escapeXml(phptype)}"`; const nullCheckbox = row.querySelector('input[name="null"]'); const nullVal = nullCheckbox.checked ? 'true' : 'false'; fieldXml += ` null="${nullVal}"`; const defaultVal = row.querySelector('input[name="default"]').value.trim(); if (defaultVal) fieldXml += ` default="${escapeXml(defaultVal)}"`; const indexVal = row.querySelector('select[name="index"]').value; if (indexVal) fieldXml += ` index="${escapeXml(indexVal)}"`; fieldXml += ' />'; xmlLines.push(fieldXml); }); // Добавляем стандартные агрегации xmlLines.push(' <aggregate alias="Resource" class="modResource" local="resource_id" foreign="id" cardinality="one" owner="foreign" />'); xmlLines.push(' <aggregate alias="Creator" class="modUser" local="createdby" foreign="id" cardinality="one" owner="foreign" />'); // Закрывающие теги xmlLines.push(' </object>'); xmlLines.push('</model>'); // Выводим результат в текстовое поле document.getElementById('output').value = xmlLines.join('\n'); } // Инициализация: добавляем обработчик для кнопки генерации document.addEventListener('DOMContentLoaded', () => { document.querySelector('.mjg_input_rows_add').addEventListener('click', addField); }); </script> </body> </html> Пошаговые инструкции / MigxDB - Делаем безграничное хранилище "объектов" в ресурсах. 11 +1
22 мая 2025, 22:41 тот же вопрос по диапозону дат. готового решения так никто и не озвучит? Готовые решения / mFilter2 фильтрация посредством Datepicker jquery 10 0
06 мая 2025, 20:21 решил таким способом получение первой картинки {set $preview = $_modx->runSnippet('ms2Gallery', [ 'resources' => $id, 'filetype' => 'image', 'limit' => 1, 'tpl' => '@FILE chunks/image_url.tpl' ])}chunks/image_url.tpl {if $files?} {foreach $files as $file} {$file['medium']} {/foreach} {/if} Вопросы / msProducts - не подключается превьюшка 17 0
18 апреля 2025, 00:03 Не работает парсинг с vk.com, vkvideo.ru Новые дополнения и их версии / [videoGallery] 1.4.0 Поддержка VK Video и ещё пара фишек 10 0
16 апреля 2025, 11:39 Не выводятся товары привязанные к данной категории, как дополнительной В админке они отображаются в обеих категориях, опубликованы, кэши сняты Showlog также их не видит {'!msProducts' | snippet : [ 'parents' => $_modx->resource.id, ]}MODX 3.1.2-pl MiniShop3 — 1.0.0-alpha Новые дополнения и их версии / MiniShop3 - 1.0.0-alpha 21 0
22 января 2024, 13:49 стоит добавить в сниппете 'isfolder' => 0 $items = $pdo->getCollection('modResource', array( 'published' => true, 'deleted' => false, 'isfolder' => 0 Вопросы / Сниппет для вывода ресурсов кириллицей в алфавитном порядке с разбивкой на 3 колонки 3 0
21 января 2024, 16:15 Это сниппет для создания списка с алфавитным указателем Вопросы / Сниппет для вывода ресурсов кириллицей в алфавитном порядке с разбивкой на 3 колонки 3 0
15 декабря 2023, 00:09 Не смог разобраться, как удалять и генерировать по одному из ключей настроек источника файлов У меня два типа превью small и medium { "small":{"wp":150,"wl":150,"q":90,"f":"webp"}, "medium":{"wp":350,"wl":350,"q":80,"f":"jpg"} }Если необходимо добавить еще один тип или изменить настройки одного из типов, то при выполнении данного кода удаляются все файлы превью обоих типов и пересоздаются заново $child->remove(); generateThumbnails();Есть ли возможность пересоздать конкретный? Вопросы / Быстро пересоздать превью продуктов с выбором дапазона через Console 2 0
20 мая 2022, 01:16 решено запуск сниппета в head <?php $getid = $_GET['id']; if ($getid != '' && is_numeric($getid)) { $url=$modx->makeUrl($modx->getOption('id', $scriptProperties, $modx->resource->get('id'))); header('HTTP/1.1 301 Moved Permanently'); header('Location: '.$url.''); echo '<meta http-equiv="refresh" content="0;URL='.$url.'"/>'; } Вопросы / Автоматический редирект с параметрического адреса сайта на дружественный урл 2 0
25 апреля 2022, 19:45 Нашел. ../assets/components/onebooking/js/web/default.js в конце задать minDate и MaxDate в формате yyyy-mm-d Новости и события / oneBooking. Последние новости 8 0
Возможно ли реализовать возможность предоплаты за доставку на сайте? Отлично, значит можно не создавать заказ пока оплата не пройдёт успешно, а поскольку класс-обработчик оплаты будет кастомный сможет сами решать какую стоимость пробрасывать. Ещё на...
Редизайн сообщества На мобилке шапка не помещается на 1 строке, плюс иконки растягиваются до овала из-за иконки, вместо того, чтобы оставаться круглыми
ImageOptimizer - WebP/AVIF и responsive <picture> для MODX 3 Выпустил новую версию [1.0.3-beta1] — 2026-07-13 Fixed — Inject сохраняет ``, `` и `` на полном HTML-документе (больше не оборачивает страни...
MiniShop3 1.11.0 при клике на radio идет пересчет итоговой суммы в orderUI, в зависимости от способов(оплаты доставки) я так поняла. попробуй код запуска события поставить ниже чем orderUI, после
Localizator3 для MODX 3: перевод полей и TV без отдельного context на язык, Vue 3 + PrimeV... Добавил localizator3_default_language
msInShopNotify Начиная с версии 3.0.0-beta добавлена поддержка MiniShop3 Минимальные требования: PHP 8.4 MODX 3.2 MiniShop3
MaxNotify Обновление 1.2.0-pl (03.07.2026) — добавлены уведомления о заявках FormIt через hook-сниппет `maxNotifyFormIt`; — добавлены уведомления о заявках SendIt через hook-...
elements/snippets/bgImage.php
Вывод изображения на странице. Параметры можно опустить или указать под разные задачи
Чанк videogalleryVideosTabs.tpl
Чанк videogalleryVideos.tpl
Вызов на странице
- установил autoRedirector
- далее через phpMyAdmin
- экспортировал со старого сайта modx_site_content
- залил в базу к новому с именем modx_site_content_old
- сравнил две базы. если у одинаковых id ресурсов значения uri не совпадают, то добавил новые редиректы в базу modx_ar_rules
- удалил дубликаты записей в modx_ar_rules
- удалил modx_site_content_old
все четенько на 7К ресурсов в несколько кликовможет кому пригодится или доработается
chunks/image_url.tpl
В админке они отображаются в обеих категориях, опубликованы, кэши сняты
Showlog также их не видит
MODX 3.1.2-pl
MiniShop3 — 1.0.0-alpha
У меня два типа превью small и medium
Если необходимо добавить еще один тип или изменить настройки одного из типов, то при выполнении данного кода удаляются все файлы превью обоих типов и пересоздаются заново
Есть ли возможность пересоздать конкретный?
запуск сниппета в head