Готовые решения

Обновление полей ресурсов на основе csv-файла иморта (modx 2.8.8 + minishop 2)

Задача была обновить поля у ресурсов (ресурсы: категории, товары; поля: основные, дополнительные (тв)).
Обновление изображений (галерея) в задачу не входило.
Возможно, кому-нибудь пригодится. Если будут корректировки/замечания, буду только рад.
Виталий
17 февраля 2026, 03:09
modx.pro
3
186
+5

Видеогалерея на MIGX. Может кому понадобится (решено)

*Помогите толком разобраться, как редактировать поля title, desc, image, duration, которые находятся внутри json массива у видео в виде отдельных полей, а не кривыми ручками

Видеогалерея на MIGX

  1. Устанавливаем VideoGallery
  2. Создаем tv с именем video тип ввода VideoGallery
  3. Создаем tv с именем videogallery. Тип ввода migx, конфигурация videogallery, выбираем шаблон для отображения
  4. Создаем сниппет VideoJsonToPlaceholders
    ! ВНИМАНИЕ в п.2 удалите пробел между & quot;

    <?php
    // Получаем параметры
    $json = $modx->getOption('json', $scriptProperties, '');
    $prefix = $modx->getOption('prefix', $scriptProperties, 'json.');
    
    // 1. Проверяем наличие данных
    if (empty($json)) {
        return 'Ошибка: JSON‑строка пуста';
    }
    
    // 2. Удаляем все & quot; из строки ! Внимание в следующей строке удалите пробел между & quot;
    $json = str_replace('& quot;', '', $json);
    
    // 3. Исправляем экранированные слеши
    $json = str_replace('\\/', '/', $json);
    
    // 4. Парсим JSON
    $data = json_decode($json, true);
    
    if (json_last_error() !== JSON_ERROR_NONE) {
        return 'Ошибка JSON: ' . json_last_error_msg() . ' (строка: ' . htmlspecialchars($json) . ')';
    }
    
    // 5. Проверяем, что результат — массив
    if (!is_array($data)) {
        return 'Ошибка: JSON не содержит массив';
    }
    
    // 6. Функция для извлечения корневого адреса (с защитой от повторного объявления)
    if (!function_exists('getRootUrl')) {
        function getRootUrl($url) {
            if (!filter_var($url, FILTER_VALIDATE_URL)) {
                return null;
            }
    
            $parsed = parse_url($url);
            if (!$parsed || !isset($parsed['scheme']) || !isset($parsed['host'])) {
                return null;
            }
    
            $root = $parsed['scheme'] . '://' . $parsed['host'];
    
            if (isset($parsed['port'])) {
                $isDefaultHttp = ($parsed['scheme'] === 'http' && $parsed['port'] === 80);
                $isDefaultHttps = ($parsed['scheme'] === 'https' && $parsed['port'] === 443);
                if (!$isDefaultHttp && !$isDefaultHttps) {
                    $root .= ':' . $parsed['port'];
                }
            }
    
            return $root;
        }
    }
    
    // 7. Устанавливаем плейсхолдеры с обработкой
    foreach ($data as $key => $value) {
        // Приводим строки к UTF‑8
        if (is_string($value)) {
            $value = mb_convert_encoding($value, 'UTF-8', 'UTF-8');
        }
    
        // Если это поле video и содержит URL — извлекаем корневой адрес
        if ($key === 'video' && !empty($value)) {
            $rootUrl = getRootUrl($value);
            if ($rootUrl) {
                $modx->setPlaceholder($prefix . 'video_root', $rootUrl);
            }
            // Сохраняем исходный URL
            $modx->setPlaceholder($prefix . 'video', $value);
        }
    
        // Преобразуем videoDuration из PT... в оптимальный формат
        if ($key === 'videoDuration') {
            if (empty($value) || !is_string($value)) {
                $value = '0 с';
            } else {
                preg_match('/PT(?:(\d+)H)?(?:(\d+)M)?(?:(\d+)S)?/', $value, $matches);
                $hours   = isset($matches[1]) ? (int)$matches[1] : 0;
                $minutes = isset($matches[2]) ? (int)$matches[2] : 0;
                $seconds = isset($matches[3]) ? (int)$matches[3] : 0;
    
                if ($hours > 0) {
                    $value = sprintf('%02d:%02d:%02d', $hours, $minutes, $seconds);
                } elseif ($minutes > 0) {
                    $value = sprintf('%02d:%02d', $minutes, $seconds);
                } else {
                    $value = $seconds . ' с';
                }
            }
        }
    
        // Подставляем значения по умолчанию для критических полей
        switch ($key) {
            case 'title':
                if (empty($value)) {
                    $value = 'Без названия';
                }
                break;
            case 'desc':
                if (empty($value)) {
                    $value = 'Описание отсутствует';
                }
                break;
        }
    
        // Устанавливаем плейсхолдер (если он ещё не установлен через парсинг)
        if (!in_array($key, ['video', 'video_root'])) {
            $modx->setPlaceholder($prefix . $key, $value);
        }
    }
    
    return '';
  5. Создаем новое MIGx поле videogallery
  6. Экспортируем туда конфиг
    {
      "formtabs": [
        {
          "caption": "Видеогалерея",
          "print_before_tabs": "0",
          "fields": [
            {
              "field": "video",
              "caption": "Видео",
              "inputTV": "video"
            }
          ],
          "pos": 1
        }
      ],
      "contextmenus": "",
      "actionbuttons": "",
      "columnbuttons": "",
      "filters": "",
      "extended": {
        "actionbuttonsperrow": 4,
        "gridload_mode": 1,
        "has_jointable": "yes"
      },
      "permissions": {},
      "fieldpermissions": "",
      "columns": [
        {
          "header": "Рендер",
          "dataIndex": "render",
          "width": 1,
          "sortable": "false",
          "show_in_grid": 0,
          "renderer": "this.renderChunk",
          "renderchunktpl": "[[!VideoJsonToPlaceholders? &json=`[[+video]]` &prefix=`video.`]]"
        },
        {
          "header": "Название",
          "dataIndex": "video_title",
          "sortable": "false",
          "show_in_grid": 1,
          "renderer": "this.renderChunk",
          "renderchunktpl": "[[+video.title]]"
        },
        {
          "header": "Видео",
          "dataIndex": "video_video",
          "sortable": "false",
          "show_in_grid": 1,
          "renderer": "this.renderChunk",
          "renderchunktpl": "<iframe src=\"[[+video.video]]\" width=\"160\" height=\"90\" frameborder=\"0\"></iframe>"
        },
        {
          "header": "Превью",
          "dataIndex": "video_image",
          "sortable": "false",
          "show_in_grid": 1,
          "renderer": "this.renderChunk",
          "renderchunktpl": "<img src=\"[[+video.image]]\" width=\"160\">"
        },
        {
          "header": "Время",
          "dataIndex": "video_duration",
          "width": 100,
          "sortable": "false",
          "show_in_grid": 1,
          "renderer": "this.renderChunk",
          "renderchunktpl": "[[+video.videoDuration]]"
        },
        {
          "header": "videoId",
          "dataIndex": "video_videoId",
          "sortable": "false",
          "show_in_grid": "0",
          "renderer": "this.renderChunk",
          "renderchunktpl": "[[+video.videoId]]"
        },
        {
          "header": "Описание",
          "dataIndex": "video_description",
          "sortable": "false",
          "show_in_grid": 1,
          "renderer": "this.renderChunk",
          "renderchunktpl": "[[+video.desc]]"
        }
      ],
      "category": ""
    }
SYAN
09 февраля 2026, 01:00
modx.pro
2
2 400
0

Сниппет getPageBlockContent для вывода блоков PageBlocks (Free версия) с других страниц в MODX

В бесплатной версии PageBlocks нет встроенного инструмента для вывода блоков с другой страницы. Этот сниппет решает задачу через xPDO-запрос к таблице pbBlockValue. Он позволяет выводить указанные блоки с любого ресурса, с опциями сортировки, лимита и обёртки.
FastDevLab
29 января 2026, 11:10
modx.pro
2 262
+2

StaticFilesPlus — автоматическое создание статических элементов с поддержкой категорий

Плагин для MODX 3, который автоматически сохраняет чанки, шаблоны, сниппеты и плагины в статические файлы при их сохранении в админке.​

Зачем это нужно?
При разработке на MODX удобно работать с элементами через IDE (PhpStorm, VS Code и др.), используя Git для версионирования. Плагин автоматизирует создание статических файлов и правильно организует их по категориям с транслитерацией русских названий.​

Возможности

  1. Автоматическое создание файлов — сохраняете элемент в админке, файл создаётся автоматически​
  2. Поддержка категорий — файлы размещаются в папках по категориям с учётом иерархии​
  3. Транслитерация — русские названия категорий преобразуются в латиницу (например: «Дизайн сайта» → «dizayn_sayta»)​
  4. Использует настройку pdotools_elements_path — не нужно хардкодить пути​
Работает с MODX 3 и PHP 8.0+​
FastDevLab
18 ноября 2025, 17:14
modx.pro
2
11 084
+5

PdoPage без jQuery

Давно делал костылями пагинацию без jQuery
недавно дошли руки поковырять PdoPage

Скажу сразу в скрипте могут быть баги
У меня с ресурсами работает отлично
ВитОс
01 октября 2025, 18:25
modx.pro
3
961
+8

MODX HTML Cache Plugin

Плагин для MODX, который сохраняет сгенерированные страницы в HTML-файлы и отдает их напрямую без парсинга MODX.
Это позволяет значительно ускорить работу сайта на фронтенде.

ЗЫ: Делался плагин в основном для статики и лендингов!!! (Если в шаблоне есть динамические данные (например, корзина, личный кабинет), лучше исключить его из кэширования.)

Файлы сохраняются в директории:
core/cache/html_pages/{template_id}/
Имя файла формируется так:
{resource_id}_{md5(uri)}.html
vectorserver
30 сентября 2025, 10:18
modx.pro
5
704
+7

Этот хук обрабатывает форму "Купить в 1 клик", создает заказ в miniShop2

Подходит для Formit, FetchIt на других потетсровать не удалось)))
Искал решение но тут на портале много заморочек с правкой скриптов JS и тп, думаю самый просто вариант это хук…
vectorserver
05 сентября 2025, 07:56
modx.pro
3
1 485
+6

Авто обновление индекса mSeach2 через cron

Может кому пригодится крон для массового обновления индексов #msearch2 #cron

Инструкция:
— создаем фай в корне msearch2_cron.php содержимое кода ниже.
— запуск к примеру curl www.ru/msearch2_cron.php

<?php

// Отключение буферизации
ignore_user_abort(true);
set_time_limit(0);
ob_implicit_flush(true);
ob_end_flush();

header('Content-Type: text/html; charset=utf-8');
echo '<pre>';
ob_flush();
flush();

define('MODX_API_MODE', true);
require 'index.php';

/** @var modX $modx */
$modx->getService('error', 'error.modError');
$modx->setLogLevel(modX::LOG_LEVEL_FATAL);
$modx->setLogTarget(XPDO_CLI_MODE ? 'ECHO' : 'HTML');

/** @var modUser $adminObj */
$adminObj = $modx->getObject('modUser', ['sudo' => 1]);
$modx->user = $adminObj;


$offset = 0;

while (true) {
    /** @var modProcessorResponse $response */
    $response = $modx->runProcessor('mgr/index/create', [
        'limit' => 1000,
        'offset' => $offset,
    ], [
        'processors_path' => MODX_CORE_PATH . 'components/msearch2/processors/'
    ]);

    if ($response->isError()) {
        echo "Ошибка: " . $response->getMessage() . "\n";
        ob_flush();
        flush();
        break;
    }

    $data = $response->getObject();
    if ($data['offset'] >= 1) {
        echo "Индексировано: {$data['offset']}\n";
        ob_flush();
        flush();
    }


    // Если offset == 0 → завершаем
    if ($data['offset'] === 0) {
        echo "Получен нулевой сдвиг. Индексация остановлена.\n";
        ob_flush();
        flush();
        break;
    }

    // Обновляем offset для следующего шага
    $offset = $data['offset'];

    // Если достигли конца
    if ($offset == 0) {
        echo "Индексация успешно завершена.\n";
        ob_flush();
        flush();
        break;
    }

    //sleep(1); // пауза между порциями (можно убрать)
}
vectorserver
11 июля 2025, 10:29
modx.pro
2
1 364
+5

Вставка CSS в <style> через маркеры и data-атрибуты

Всем добра! Пишу впервые статью, и повод для неё оказался вполне практичным: нужно было повысить показатель First Paint на одном из проектов. В процессе оптимизации стало понятно, что стандартное подключение CSS через

<link rel="stylesheet">

Становится узким горлышком — оно замедляет отрисовку и задерживает появление контента на экране.
Чтобы этого избежать, было решено встроить критически важные стили прямо в HTML, используя тег style.
Так браузер сразу видит нужные правила и начинает отрисовку без лишних пауз.

Дмитрий Середюк
02 июня 2025, 13:27
modx.pro
3
1 784
+5

Проверка на новые файлы с уведомлением в телегу

Здравствуйте.

Прочитал новый топик о новом нашествии вирусов, которые меняют файлы и что-то там «майнят» создавая нагрузку.
Решил поделиться своим простым скриптом, который контролирует появление новых файлов их изменения, и если таковые будут выявлены, вышлет уведомление в телеграм. Нужно поместить данный скрипт в папку в корне сайта.
Например, detect/file_change_detector.php

Я например, запускаю раз в 6 часов по крону.

P.S.
Пишите, если решение будет востребовано могу создать компонент для MODX

Update:
Компонент создан для MODX2 и MODX3. Загрузил в репозиторий, жду модерации.

Ivan K.
15 мая 2025, 13:43
modx.pro
5
2 031
+9