Файловые элементы pdoTools — это возможность загружать чанки, сниппеты и шаблоны напрямую из файлов на диске вместо хранения в базе данных MODX. Это упрощает командную разработку через Git, ускоряет работу с кодом в IDE и позволяет использовать современные инструменты разработки. В этом уроке разберём как настроить, использовать и оптимизировать файловые элементы в связке с шаблонизатором Fenom.
- Что такое файловые элементы
- Преимущества файловых элементов
- Версионный контроль через Git
- Работа в профессиональной IDE
- Производительность
- Модульность и переиспользование
- Интеграция с CI/CD
- Наследование шаблонов через Fenom
- Настройка pdoTools для работы с файлами
- Системные настройки
- Поддерживаемые расширения файлов
- Базовый синтаксис: биндинг @FILE
- Загрузка через PHP API
- Кастомный путь к файлам
- Вызов в классических тегах MODX
- Работа с Fenom: include, extends, наследование
- Include — вставка фрагментов
- Extends — наследование шаблонов
- Источники шаблонов в Fenom
- Вызов через модификаторы
- Структура проекта и организация файлов
- Рекомендуемая структура
- Принципы организации
- Кэширование файловых элементов
- Поведение по умолчанию
- Включение кэша Fenom
- Настройка опций Fenom
- Нативный файловый кэш Fenom
- Практические примеры для реальных проектов
- Пример 1. Шаблон страницы с наследованием
- Пример 2. Модульные чанки с параметрами
- Пример 3. Файловый сниппет для API
- Пример 4. Плагины с файловой логикой
- Безопасность и подводные камни
- Защита файлов от прямого доступа
- Валидация путей
- Права доступа к файлам
- Типичные ошибки
- Заключение и лучшие практики
- Лучшие практики
Что такое файловые элементы
Файловые элементы — это чанки, сниппеты и шаблоны, которые хранятся в файловой системе сервера вместо таблиц базы данных. pdoTools загружает их динамически через специальный биндинг @FILE.
Классический подход MODX:
- Чанки → таблица
modx_site_htmlsnippets - Сниппеты → таблица
modx_site_snippets - Шаблоны → таблица
modx_site_templates
Подход с файловыми элементами:
- Чанки → файлы
.tplили.html - Сниппеты → файлы
.php - Шаблоны → файлы
.tplс поддержкой Fenom
Все элементы загружаются из директории, указанной в системной настройке pdotools_elements_path (по умолчанию {core_path}components/pdotools/elements/).
Преимущества файловых элементов
Версионный контроль через Git
Храните весь код в репозитории: делайте коммиты, ветки, pull-request’ы без экспорта/импорта элементов из БД. Команда видит все изменения в diff’ах.
Пример workflow:
git diff chunks/header.tpl
# Видны все изменения в чанке
git commit -m "Добавил мобильное меню в header"
git push origin feature/mobile-menu
Работа в профессиональной IDE
Полная поддержка PhpStorm, VS Code, Sublime Text: автодополнение, подсветка синтаксиса, refactoring, встроенная отладка. В админке MODX этого нет.
Производительность
Загрузка файла с диска через opcache быстрее, чем SELECT из БД, особенно для больших элементов. Меньше нагрузка на MySQL.
Модульность и переиспользование
Разбивайте код на логические модули:
chunks/
├── common/header.tpl # Общая шапка
├── common/footer.tpl # Общий футер
├── blog/post.tpl # Карточка поста
└── shop/product.tpl # Карточка товара
Подключайте через {include} без дублирования кода.
Интеграция с CI/CD
Автоматизируйте деплоймент через GitLab CI, GitHub Actions, Jenkins — файлы автоматически попадают на сервер без ручного копирования в админку.
Наследование шаблонов через Fenom
Используйте {extends} для создания базовых layout’ов — это невозможно для элементов из БД без хаков.
Настройка pdoTools для работы с файлами
Системные настройки
Путь: Система → Настройки → pdoTools
| Настройка | Значение | Описание |
|---|---|---|
pdotools_elements_path |
{core_path}elements/ |
Базовая директория для файловых элементов |
pdotools_fenom_parser |
Да | Обязательно для работы {include 'file:...'} |
pdotools_fenom_cache |
Нет (dev) / Да (prod) | Кэширование скомпилированных Fenom-шаблонов |
pdotools_fenom_options |
{"auto_reload":true} |
JSON-опции Fenom (см. раздел Кэширование) |
Рекомендация: создайте свою папку вне core/components/pdotools/:
# В настройках укажите
pdotools_elements_path = {base_path}elements/
# Структура
/elements/
├── chunks/
├── snippets/
└── templates/
Это защитит файлы от случайного удаления при обновлении pdoTools.
Поддерживаемые расширения файлов
- Чанки:
.tpl,.html - Сниппеты:
.php - Другие расширения игнорируются для безопасности
Базовый синтаксис: биндинг @FILE
Загрузка через PHP API
Чанк:
if ($pdoTools = $modx->getService('pdoTools')) {
$chunk = $pdoTools->getChunk('@FILE chunks/my_chunk.tpl', [
'placeholder' => 'value'
]);
echo $chunk;
}
Сниппет:
if ($pdoTools = $modx->getService('pdoTools')) {
$result = $pdoTools->runSnippet('@FILE snippets/my_snippet.php', [
'param' => 'value'
]);
return $result;
}
Кастомный путь к файлам
Если файлы находятся вне pdotools_elements_path, укажите elementsPath:
$chunk = $pdoTools->getChunk('@FILE custom/my_chunk.tpl', [
'placeholder' => 'value',
'elementsPath' => MODX_ASSETS_PATH . 'mytheme/'
]);
Теперь файл будет загружен из assets/mytheme/custom/my_chunk.tpl.
Вызов в классических тегах MODX
В контенте ресурса или шаблоне:
[[$@FILE chunks/header.tpl]]
[[!@FILE snippets/latest_news.php? &limit=`5`]]
Префикс ! делает вызов некешированным.
Работа с Fenom: include, extends, наследование
Fenom добавляет мощные инструменты шаблонизации, недоступные в классических тегах MODX.
Include — вставка фрагментов
Синтаксис: {include 'file:path/to/file.tpl'}
Пример в шаблоне:
<!DOCTYPE html>
<html>
<head>
{include 'file:chunks/common/head.tpl'}
</head>
<body>
{include 'file:chunks/common/header.tpl'}
<main>{$content}</main>
{include 'file:chunks/common/footer.tpl'}
</body>
</html>
Передача параметров:
{include 'file:chunks/button.tpl'
text='Купить'
url='/shop'
class='btn-primary'
}
В chunks/button.tpl:
<a href="{$url}" class="btn {$class}">
{$text}
</a>
Extends — наследование шаблонов
Создайте базовый layout и переопределяйте блоки в дочерних шаблонах.
Базовый шаблон (templates/base.tpl):
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<title>{block 'title'}{$_modx->config.site_name}{/block}</title>
{block 'head'}{/block}
</head>
<body>
{include 'file:chunks/common/header.tpl'}
<main class="container">
{block 'content'}
<p>Контент по умолчанию</p>
{/block}
</main>
{include 'file:chunks/common/footer.tpl'}
{block 'scripts'}{/block}
</body>
</html>
Дочерний шаблон (templates/blog_post.tpl):
{extends 'file:templates/base.tpl'}
{block 'title'}
{$pagetitle} | {$_modx->config.site_name}
{/block}
{block 'head'}
<meta name="description" content="{$description}">
<link rel="stylesheet" href="/assets/css/blog.css">
{/block}
{block 'content'}
<article class="post">
<h1>{$pagetitle}</h1>
<time>{$publishedon | date:'%d.%m.%Y'}</time>
<div class="post-content">
{$content}
</div>
{if $tags}
{include 'file:chunks/blog/tags.tpl' tags=$tags}
{/if}
</article>
{/block}
{block 'scripts'}
<script src="/assets/js/comments.js"></script>
{/block}
Использование в MODX:
В шаблоне MODX (в БД) укажите всего одну строку:
{include 'file:templates/blog_post.tpl'}
Весь layout загрузится из файлов с наследованием от base.tpl.
Источники шаблонов в Fenom
Файловые: {include 'file:path.tpl'}
Из БД (чанк): {include 'myChunk'} или {include '10'} (по ID)
Из шаблона MODX: {include 'template:MyTemplate'} или {include 'template:1'}
Вызов через модификаторы
Чанк:
{'@FILE chunks/my_chunk.tpl' | chunk : ['name' => 'John']}
Сниппет:
{'@FILE snippets/fetch_data.php' | snippet : ['limit' => 10]}
С кастомным путём:
{$_modx->getChunk('@FILE custom/chunk.tpl', [ 'param' => 'value', 'elementsPath' => '/path/to/files/' ])}
Структура проекта и организация файлов
Рекомендуемая структура
elements/
├── chunks/ # Чанки (UI-фрагменты)
│ ├── common/ # Общие элементы
│ │ ├── head.tpl
│ │ ├── header.tpl
│ │ ├── footer.tpl
│ │ └── sidebar.tpl
│ ├── blog/ # Блог
│ │ ├── post_card.tpl # Карточка поста
│ │ ├── post_full.tpl # Полный пост
│ │ └── comments.tpl
│ ├── shop/ # Магазин
│ │ ├── product_card.tpl
│ │ ├── product_full.tpl
│ │ └── cart.tpl
│ └── partials/ # Переиспользуемые компоненты
│ ├── button.tpl
│ ├── modal.tpl
│ └── form_field.tpl
├── snippets/ # Сниппеты (логика)
│ ├── utils/ # Утилиты
│ │ ├── date_formatter.php
│ │ ├── image_resizer.php
│ │ └── cache_helper.php
│ ├── api/ # API-интеграции
│ │ ├── fetch_news.php
│ │ └── send_email.php
│ └── custom/ # Кастомная логика
│ └── calculate_price.php
├── templates/ # Шаблоны страниц
│ ├── base.tpl # Базовый layout
│ ├── home.tpl # Главная
│ ├── page.tpl # Обычная страница
│ ├── blog_list.tpl # Список постов
│ └── blog_post.tpl # Отдельный пост
└── plugins/ # Плагины (если нужны файловые)
└── custom_events.php
Принципы организации
- Группировка по функциональности:
chunks/blog/,chunks/shop/ - Переиспользуемость:
partials/для универсальных компонентов - Разделение логики и представления: сниппеты отдельно от чанков
- Говорящие имена:
post_card.tplвместоpc.tpl
Кэширование файловых элементов
Поведение по умолчанию
- Файловые сниппеты не кэшируются — выполняются каждый раз
- Файловые чанки через @FILE кэшируются при включении
pdotools_fenom_cache
Включение кэша Fenom
Системная настройка:
pdotools_fenom_cache = Yes
Скомпилированные шаблоны сохраняются в core/cache/default/fenom/:
cache/default/fenom/
├── file/ # Файловые элементы
│ └── 5f4dcc3b5aa765d61d8327deb882cf99.php
├── chunk/ # Чанки из БД
│ └── 90.cache.php
└── inline/ # @INLINE чанки
└── 35e115c27fdc3814.php
Настройка опций Fenom
Путь: pdotools_fenom_options (JSON)
Development (разработка):
{
"force_compile": true,
"disable_cache": true,
"auto_reload": true,
"force_include": true
}
force_compile— рекомпиляция при каждом запросе (видите изменения сразу)auto_reload— автообновление при изменении файлаdisable_cache— отключение кэша (для отладки)
Production (продакшн):
{
"force_compile": false,
"disable_cache": false,
"auto_reload": false,
"force_include": true
}
Максимальная скорость — шаблоны компилируются один раз и кэшируются.
Нативный файловый кэш Fenom
Для работы только с файлами (без @FILE) используйте {include 'file:...'} — Fenom сам управляет кэшем эффективнее:
{* Рекомендуемый способ *}
{include 'file:chunks/header.tpl'}
{* Вместо *}
{$_modx->getChunk('@FILE chunks/header.tpl')}
Практические примеры для реальных проектов
Пример 1. Шаблон страницы с наследованием
В MODX создайте шаблон «Blog Post» (в БД):
{include 'file:templates/blog_post.tpl'}
Файл templates/base.tpl (базовый layout):
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{block 'title'}{$_modx->config.site_name}{/block}</title>
{block 'meta'}{/block}
<link rel="stylesheet" href="/assets/css/main.css">
{block 'styles'}{/block}
</head>
<body>
{include 'file:chunks/common/header.tpl'}
{block 'content'}
<div class="container">
<h1>Контент по умолчанию</h1>
</div>
{/block}
{include 'file:chunks/common/footer.tpl'}
<script src="/assets/js/main.js"></script>
{block 'scripts'}{/block}
</body>
</html>
Файл templates/blog_post.tpl:
{extends 'file:templates/base.tpl'}
{block 'title'}
{$pagetitle} | Блог | {$_modx->config.site_name}
{/block}
{block 'meta'}
<meta name="description" content="{$description ?: $introtext}">
<meta property="og:title" content="{$pagetitle}">
<meta property="og:image" content="{$image}">
{/block}
{block 'content'}
<article class="blog-post container">
<h1>{$pagetitle}</h1>
<div class="post-meta">
<time datetime="{$publishedon}">{$publishedon | date:'%d.%m.%Y'}</time>
<span class="author">Автор: {$createdby | userinfo:'fullname'}</span>
</div>
<div class="post-content">
{$content}
</div>
{if $tags}
<div class="tags">
{foreach $tags as $tag}
<span class="tag">{$tag}</span>
{/foreach}
</div>
{/if}
{include 'file:chunks/blog/related_posts.tpl' id=$id}
</article>
{/block}
{block 'scripts'}
<script src="/assets/js/comments.js"></script>
{/block}
Пример 2. Модульные чанки с параметрами
Файл chunks/partials/button.tpl:
<a href="{$url}"
class="btn {$class ?: 'btn-primary'} {$size ?: ''}"
{if $target}target="{$target}"{/if}
{if $disabled}disabled{/if}>
{if $icon}
<i class="icon-{$icon}"></i>
{/if}
{$text}
</a>
Использование:
{include 'file:chunks/partials/button.tpl'
text='Купить сейчас'
url='/cart/add'
class='btn-success'
icon='cart'
}
{include 'file:chunks/partials/button.tpl'
text='Подробнее'
url=$link
class='btn-outline'
}
Пример 3. Файловый сниппет для API
Файл snippets/api/fetch_news.php:
<?php
/**
* Загружает новости из внешнего API
*
* @param int $limit Количество новостей
* @param string $category Категория
* @return string JSON
*/
$limit = (int)($limit ?? 5);
$category = $category ?? 'all';
// Ваша логика
$news = fetchFromAPI($category, $limit);
return json_encode($news);
Вызов в Fenom:
{var $news_json = '@FILE snippets/api/fetch_news.php' | snippet : ['limit' => 10, 'category' => 'tech']}
{var $news = $news_json | json_decode : true}
{foreach $news as $item}
<div class="news-item">
<h3>{$item.title}</h3>
<p>{$item.description}</p>
</div>
{/foreach}
Пример 4. Плагины с файловой логикой
Создайте плагин в MODX (в БД) с событием OnLoadWebDocument:
<?php
if ($pdoTools = $modx->getService('pdoTools')) {
$pdoTools->runSnippet('@FILE plugins/seo_redirect.php', $scriptProperties);
}
Файл plugins/seo_redirect.php:
<?php
/**
* SEO редиректы с www на без www
*/
switch ($modx->event->name) {
case 'OnLoadWebDocument':
$host = $_SERVER['HTTP_HOST'];
if (strpos($host, 'www.') === 0) {
$new_host = str_replace('www.', '', $host);
$url = 'https://' . $new_host . $_SERVER['REQUEST_URI'];
$modx->sendRedirect($url, ['responseCode' => 'HTTP/1.1 301 Moved Permanently']);
}
break;
}
Безопасность и подводные камни
Защита файлов от прямого доступа
Проблема: файлы .tpl и .php доступны по URL вроде site.com/elements/chunks/header.tpl.
Решение 1: храните файлы вне web-root (в core/elements/ вместо assets/elements/).
Решение 2: создайте .htaccess в папке elements/:
<Files ~ "\.(tpl|html|php)$">
Require all denied
</Files>
Для Nginx:
location ~* \.(tpl|html|php)$ {
deny all;
}
Валидация путей
Опасно:
// $_GET['file'] может быть '../../../etc/passwd'
$chunk = $pdoTools->getChunk('@FILE ' . $_GET['file']);
Безопасно:
$allowed_chunks = ['header', 'footer', 'sidebar'];
$file = in_array($_GET['chunk'], $allowed_chunks)
? $_GET['chunk']
: 'default';
$chunk = $pdoTools->getChunk('@FILE chunks/' . $file . '.tpl');
Права доступа к файлам
Установите корректные права:
chmod 755 elements/
chmod 644 elements/chunks/*.tpl
chmod 755 elements/snippets/*.php
Владелец — пользователь веб-сервера (обычно www-data или apache).
Типичные ошибки
1. Файл не найден:
Error loading chunk '@FILE chunks/missing.tpl'
Проверьте путь относительно pdotools_elements_path и существование файла.
2. Синтаксическая ошибка в Fenom:
Fenom\CompileException: Unexpected token...
Включите &showLog=1 в вызове сниппета или проверьте логи MODX в core/cache/logs/.
3. Кэш не обновляется:
Если force_compile = false, очистите кэш MODX или удалите core/cache/default/fenom/.
4. Конфликт с путями:
// Неправильно — ищет в pdotools_elements_path + /absolute/path
$pdoTools->getChunk('@FILE /absolute/path/chunk.tpl');
// Правильно
$pdoTools->getChunk('@FILE chunk.tpl', [
'elementsPath' => '/absolute/path/'
]);
Заключение и лучшие практики
Файловые элементы pdoTools — это современный подход к разработке на MODX. Вы научились:
- Настраивать pdoTools для работы с файлами через
pdotools_elements_path. - Использовать биндинг
@FILEдля загрузки чанков и сниппетов. - Применять Fenom с
{include}и{extends}для модульных шаблонов. - Организовывать структуру проекта логично и масштабируемо.
- Оптимизировать через кэширование Fenom.
- Обеспечивать безопасность через права доступа и валидацию.
Лучшие практики
- Используйте
{include 'file:...'}вместо@FILE— быстрее благодаря нативному кэшу Fenom. - Создавайте базовые layout’ы через
{extends}— избегайте дублирования. - Группируйте файлы по функциональности —
chunks/blog/,chunks/shop/. - Включайте
force_compileтолько на dev — на продакшне отключайте. - Защищайте файлы через .htaccess — запретите прямой доступ к
.tplи.php. - Используйте Git — коммитьте изменения, создавайте ветки, делайте code review.
- Документируйте сниппеты — добавляйте PHPDoc с описанием параметров.
Файловые элементы в pdoTools — это шаг к современному веб-разработке в MODX. Они сочетают гибкость файловой системы с мощью Fenom, делая проекты масштабируемыми и удобными. Для глубокого погружения изучите документацию pdoTools и экспериментируйте с примерами.






