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

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

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

Возможности

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

Установка

  1. Создайте новый плагин в админке: Элементы → Плагины → Создать плагин
  2. Скопируйте код плагина (см. ниже)
  3. Привяжите к событиям:​
    • OnChunkFormSave — для чанков;
    • OnTempFormSave — для шаблонов;

    • OnSnipFormSave — для сниппетов;
    • OnPluginFormSave — для плагинов;
  4. Сохраните.
Настройка (опционально)

Если хотите изменить базовый путь сохранения файлов, поправьте системную настройку: pdotools_elements_path

По умолчанию файлы сохраняются в core/elements/​
Структура файлов

Плагин создаёт следующую структуру:

core/elements/
├── chunks/
│   ├── header/
│   │   └── mainMenu.tpl
│   └── dizayn_sayta/
│       └── colors.tpl
├── templates/
│   └── osnovnye/
│       └── base.tpl
├── snippets/
│   └── helpers/
│       └── getPrice.php
└── plugins/
    └── custom/
        └── myPlugin.php
Примеры транслитерации категорий

  • Дизайн → dizayn
  • Дизайн сайта → dizayn_sayta
  • Header & Footer → header_footer
  • API Helpers → api_helpers

Код плагина
<?php
/**
 * StaticFilesPlus
 * 
 * @events OnChunkFormSave,OnTempFormSave,OnSnipFormSave,OnPluginFormSave
 */

$eventName = $modx->event->name;

$events = [
    'OnChunkFormSave' => ['type' => 'chunks', 'extension' => 'tpl'],
    'OnTempFormSave' => ['type' => 'templates', 'extension' => 'tpl'],
    'OnSnipFormSave' => ['type' => 'snippets', 'extension' => 'php'],
    'OnPluginFormSave' => ['type' => 'plugins', 'extension' => 'php']
];

if (!isset($events[$eventName])) {
    return;
}

$config = $events[$eventName];

// Получаем элемент
$element = null;
switch ($eventName) {
    case 'OnChunkFormSave':
        $element = isset($chunk) ? $chunk : null;
        break;
    case 'OnTempFormSave':
        $element = isset($template) ? $template : null;
        break;
    case 'OnSnipFormSave':
        $element = isset($snippet) ? $snippet : null;
        break;
    case 'OnPluginFormSave':
        $element = isset($plugin) ? $plugin : null;
        break;
}

if (!$element) {
    return;
}

// Получаем базовый путь
$basePath = $modx->getOption('pdotools_elements_path', null, '');

if (empty($basePath)) {
    $basePath = MODX_CORE_PATH . 'elements/';
} else {
    if (strpos($basePath, '/') !== 0 && strpos($basePath, ':') === false) {
        $basePath = MODX_BASE_PATH . $basePath;
    }
}

$basePath = rtrim($basePath, '/') . '/';
$typePath = $basePath . $config['type'] . '/';

// Получаем путь категории с транслитерацией через MODX API
$categoryPath = '';
$categoryId = (int) $element->get('category');

if ($categoryId > 0) {
    $path = [];
    $category = $modx->getObject('modCategory', $categoryId);
    
    if ($category) {
        $maxDepth = 10;
        $depth = 0;
        
        while ($category && $depth < $maxDepth) {
            $categoryName = (string) $category->get('category');
            
            if (!empty($categoryName)) {
                // Используем встроенный метод MODX для транслитерации
                $categoryName = $modx->filterPathSegment($categoryName);
                
                // Заменяем пробелы на подчёркивания
                $categoryName = str_replace([' ', '-'], '_', $categoryName);
                
                // Приводим к нижнему регистру
                $categoryName = strtolower($categoryName);
                
                if (!empty($categoryName)) {
                    array_unshift($path, $categoryName);
                }
            }
            
            $parentId = (int) $category->get('parent');
            if ($parentId > 0) {
                $category = $modx->getObject('modCategory', $parentId);
            } else {
                break;
            }
            $depth++;
        }
    }
    
    if (!empty($path)) {
        $categoryPath = implode('/', $path) . '/';
    }
}

$fullPath = $typePath . $categoryPath;

// Создаём директорию
if (!file_exists($fullPath)) {
    if (!mkdir($fullPath, 0755, true) && !is_dir($fullPath)) {
        return;
    }
}

// Формируем имя файла
$elementName = $element->get('name');
if (empty($elementName)) {
    return;
}

$fileName = $elementName . '.' . $config['extension'];
$filePath = $fullPath . $fileName;

// Получаем содержимое
$content = (string) $element->get('content');

if ($config['extension'] === 'php' && strpos($content, '<?php') !== 0) {
    $content = "<?php\n" . $content;
}

// Сохраняем файл
if (file_put_contents($filePath, $content) === false) {
    return;
}

// Обновляем элемент
$relativePath = str_replace($basePath, '', $filePath);

$mediaSourceId = 1;
$staticMediaSource = $modx->getObject('sources.modMediaSource', ['class_key' => 'sources.modFileMediaSource']);
if ($staticMediaSource) {
    $mediaSourceId = (int) $staticMediaSource->get('id');
}

$element->set('static', true);
$element->set('static_file', $relativePath);
$element->set('source', $mediaSourceId);
$element->save();
Преимущества перед аналогом StaticFiles:

  1. Использует настройку pdotools_elements_path вместо жёстко заданного пути
  2. Создаёт подпапки по категориям
  3. Поддерживает вложенные категории
  4. Транслитерирует русские названия
  5. Работает с MODX 3
Совместимость:
  • MODX Revolution 3.x
  • PHP 8.0+
Полезные настройки
После установки рекомендуется отключить кеширование для корректной работы:​
  • cache_default → false
  • cache_resource → false
Примечания

  • Плагин автоматически добавляет <?php в начало PHP-файлов, если его нет.
  • Если категория не задана, файл сохраняется в корень папки типа элемента.
  • Работает только с событиями сохранения формы (OnFormSave), не с прямым сохранением объектов.
Создано для упрощения работы с MODX через IDE и Git.​

Вопросы, критика и предложения приветствуются!
FastDevLab
Вчера в 17:14
modx.pro
174
+3

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

Артур Шевченко
8 часов назад
0
Если хотите изменить базовый путь сохранения файлов, поправьте системную настройку: pdotools_elements_path
Т.е. pdoTools установлен, зачем же тогда создавать статические чанки, шаблоны и сниппеты?
    FastDevLab
    8 часов назад
    0
    Статические элементы нужны для работы с Git, версионирования и командной разработки. Удобно создавать элементы быстро в админке, а затем дорабатывать их в IDE с подсветкой синтаксиса, автодополнением и всеми инструментами современного редактора. Также это позволяет синхронизировать элементы между окружениями (локальная → тестовая → продакшн) через систему контроля версий, что критично для командной работы.
      Артур Шевченко
      8 часов назад
      0
      Спрошу по-другому, почему просто не использовать файловые элементы, не создавая их в админке?
        FastDevLab
        7 часов назад
        0
        Ну я к примеру очень часто использую плагин PageBlocks (free версию — он не поддерживает файловые чанки (которых нет в админке) в своих вызовах — ну или я что то не знаю). В общем я создаю в нем нужные конфиги блоков, создаю для них чанки — этим чанкам после сохранения, ставится галка статический и создается файловый чанк, в котором я уже потом пишу код (как то так)
    Авторизуйтесь или зарегистрируйтесь, чтобы оставлять комментарии.
    4