Кастомные сниппеты MODX: быстрые PHP-решения с pdoTools

Стандартные сниппеты MODX часто работают медленно из-за лишних запросов к базе, что тормозит сайт и раздражает пользователей. Мы разрабатываем кастомные PHP-сниппеты с использованием pdoTools, оптимизируя каждый запрос и внедряя кэширование. Наша команда реализует решения под ключ — от аудита до поддержки, обеспечивая стабильную работу даже при высоких нагрузках.

Разработка и обслуживание любых видов сайтов:

Информационные сайты или веб-приложения
Сайты визитки, landing page, корпоративные сайты, онлайн каталоги, квиз, промо-сайты, блоги, новостные ресурсы, информационные порталы, форумы, агрегаторы
Сайты или веб-приложения электронной коммерции
Интернет-магазины, B2B-порталы, маркетплейсы, онлайн-обменники, кэшбэк-сайты, биржи, дропшиппинг-платформы, парсеры товаров
Веб-приложения для управления бизнес-процессами
CRM-системы, ERP-системы, корпоративные порталы, системы управления производством, парсеры информации
Сайты или веб-приложения электронных услуг
Доски объявлений, онлайн-школы, онлайн-кинотеатры, конструкторы сайтов, порталы предоставления электронных услуг, видеохостинги, тематические порталы

Это лишь некоторые из технических типов сайтов, с которыми мы работаем, и каждый из них может иметь свои специфические особенности и функциональность, а также быть адаптированным под конкретные потребности и цели клиента

Услуги, которые мы предлагаем
Показано 1 из 1Все 2062 услуг
Кастомные сниппеты MODX: быстрые PHP-решения с pdoTools
Средний
~2-3 дня
Часто задаваемые вопросы

Типовой сниппет — это копипаста без оптимизации

Представьте: ваш каталог товаров на MODX загружается 5 секунд, а каждый клик по категории — вечность. Причина — неоптимизированные сниппеты, которые делают десятки запросов к базе. Типовая ситуация: разработчик скопировал первый попавшийся код, не подумав о кэшировании. Результат — N+1 запросов, падение производительности и негативный пользовательский опыт. Как это исправить? Использовать правильные паттерны.

Разработка сниппета MODX часто начинается с копирования первого попавшегося примера из документации. Результат — N+1 запросов, отсутствие кэширования и уязвимости, которые превращают простую задачу в тормоз для всего сайта. Мы используем проверенные архитектурные паттерны: единый запрос, кэширование и строгую типизацию параметров. Более 5 лет опыта и более 50 проектов на MODX позволяют нам создавать сниппеты, которые выдерживают тысячи запросов без потери производительности.

Как избежать N+1 запросов в MODX?

Проблема N+1 возникает, когда вы получаете коллекцию ресурсов, а затем для каждого подгружаете TV-значения через getTVValue в цикле. При 100 ресурсах это 101 SQL-запрос. Решение — использовать JOIN или pdoFetch. Нативный MODX API позволяет написать JOIN вручную, но pdoTools делает это автоматически и быстрее. Подробнее о проблеме читайте в статье N+1 query problem.\n

Почему важно кэшировать сниппеты?

Кэширование снижает нагрузку на базу данных и ускоряет страницу. Без кэша каждый вызов сниппета — это SQL-запрос. На проекте с каталогом 5000 товаров исходный сниппет выполнялся 4 секунды. После добавления кэширования время упало до 0.2 секунды для последующих запросов. Кэш нужно инвалидировать при изменении данных или устанавливать время жизни, например, 30 минут.

Структура сниппета с безопасной выборкой

Нативный запрос с JOIN

<?php
// Сниппет ProductList
// Вызов: [[!ProductList? &category=`5` &limit=`12` &sort=`price`]]
// Получить параметры (с default значениями)
$categoryId = (int)($scriptProperties['category'] ?? 0);
$limit = (int)($scriptProperties['limit'] ?? 10);
$offset = (int)($scriptProperties['offset'] ?? 0);
$sortField = $scriptProperties['sort'] ?? 'menuindex';
$sortDir = $scriptProperties['sortdir'] ?? 'ASC';
$tpl = $scriptProperties['tpl'] ?? 'productCard';

// Запрос к ресурсам через MODX API
$c = $modx->newQuery('modResource');
$c->where([
    'parent' => $categoryId,
    'published' => 1,
    'deleted' => 0,
    'class_key' => 'modDocument',
]);

// Получить TV значения через Join
$c->innerJoin('modTemplateVarResource', 'TVPrice', [
    'TVPrice.tmplvarid' => $modx->getObject('modTemplateVar', ['name' => 'price'])->id,
    'TVPrice.contentid = modResource.id',
]);
$c->select('modResource.*, TVPrice.value AS price');
$c->sortby($sortField, $sortDir);
$c->limit($limit, $offset);
$resources = $modx->getCollection('modResource', $c);

if (empty($resources)) return '';

$output = '';
foreach ($resources as $resource) {
    $data = array_merge($resource->toArray(), [
        'price' => $resource->get('price'),
        'link' => $modx->makeUrl($resource->id, '', '', 'full'),
        'image' => $resource->getTVValue('product_image'),
    ]);
    // Чанк для вывода карточки
    $output .= $modx->getChunk($tpl, $data);
}

return $output;

Сниппет с pdoTools

<?php // Сниппет ProductSearch с pdoTools
if (!$modx->loadClass('pdoFetch', MODX_CORE_PATH . 'components/pdotools/model/pdotools/', false, true)) {
    return 'pdoTools не установлен';
}
$pdoFetch = new pdoFetch($modx, $scriptProperties);
$pdoFetch->addWhere([
    'modResource.parent' => (int)($scriptProperties['category'] ?? 0),
    'modResource.published' => 1,
]);
// TV join
$pdoFetch->addTVs('price,product_image,short_description');
$result = $pdoFetch->run();
return $result;

Кэширование результатов

<?php
// Кэшировать результат на 30 минут
$cacheKey = 'products_' . md5(json_encode($scriptProperties));
$cacheOptions = [
    xPDO::OPT_CACHE_KEY => 'default',
    xPDO::OPT_CACHE_EXPIRES => 1800
];
$cached = $modx->cacheManager->get($cacheKey, $cacheOptions);
if ($cached !== null) return $cached;
// ... запрос ...
$output = generateOutput($resources);
$modx->cacheManager->set($cacheKey, $output, 1800, $cacheOptions);
return $output;

Интеграция с внешним API

<?php // Сниппет WeatherWidget — погода из OpenWeatherMap
$city = $scriptProperties['city'] ?? 'Moscow';
$apiKey = $modx->getOption('weather_api_key');
$tpl = $scriptProperties['tpl'] ?? 'weatherWidget';
$cacheKey = 'weather_' . $city;
$cached = $modx->cacheManager->get($cacheKey, [xPDO::OPT_CACHE_EXPIRES => 1800]);
if ($cached !== null) {
    return $modx->getChunk($tpl, $cached);
}
$url = "https://api.openweathermap.org/data/2.5/weather?q={$city}&appid={$apiKey}&units=metric&lang=ru";
$response = file_get_contents($url);
if (!$response) return '';
$data = json_decode($response, true);
if (!$data || $data['cod'] !== 200) return '';
$weather = [
    'city' => $data['name'],
    'temp' => round($data['main']['temp']),
    'feels_like' => round($data['main']['feels_like']),
    'description' => $data['weather'][0]['description'],
    'icon' => "https://openweathermap.org/img/wn/{$data['weather'][0]['icon']}@2x.png",
    'humidity' => $data['main']['humidity'],
];
$modx->cacheManager->set($cacheKey, $weather, 1800);
return $modx->getChunk($tpl, $weather);

Какие параметры передавать в сниппет?

[[!ProductList? &category=`[[*id]]` &limit=`12` &tpl=`productCardTpl` &sort=`price` &sortdir=`ASC` ]] 

! перед именем — некэшированный вызов (динамический контент). Без ! — кэшированный (статический блок, одинаковый для всех).

Таблица сравнения подходов

Аспект Нативный MODX pdoTools С кэшированием
Количество SQL-запросов N+1 (коллекция + TV) 1 (один JOIN) 1 раз, затем из кэша
Простота написания Требуется ручной JOIN Автоматический подгруз TV Дополнительно 3 строки
Производительность на 1000 ресурсов ~2–3 с ~0.3–0.5 с ~0.01 с после первого запроса
Поддержка фильтров Ручное добавление where Встроенные addWhere Не влияет

Таблица типовых параметров сниппета

Параметр Тип Описание Default
category int ID родительского ресурса 0
limit int Количество выводимых записей 10
sort string Поле сортировки menuindex
sortdir string Направление сортировки (ASC/DESC) ASC
tpl string Имя чанка для вывода productCard

Типичные ошибки при разработке сниппетов

  • N+1 запросы: получение TV через getTVValue в цикле. Решение — JOIN или pdoFetch.
  • Отсутствие фильтрации входных данных: параметры без приведения типа (категория — строка, а не int).
  • Игнорирование кэширования: каждый вызов сниппета грузит БД, даже если данные не изменились.
  • Жёстко зашитые ID ресурсов: используйте плейсхолдеры и параметры.
Чек-лист: как не допустить ошибок
  • [ ] Использовать prepared statements
  • [ ] Приводить все входные параметры к нужному типу
  • [ ] Добавить кэширование с уникальным ключом
  • [ ] Использовать pdoFetch для сложных выборок
  • [ ] Документировать параметры и чанки

Что входит в работу

  • Исходный код сниппета с комментариями.
  • Документация: описание параметров, примеры вызова, описание логики.
  • Настройка кэширования: подбор времени жизни и ключа.
  • Инструкция по установке: добавление сниппета, создание чанков, тестирование.
  • Гарантия поддержки: если возникнут вопросы, мы поможем в течение месяца после сдачи.

Процесс разработки сниппета под ключ

  1. Аналитика: изучаем ТЗ, какие данные выводить, откуда брать, условия фильтрации.
  2. Проектирование: определяем структуру запроса, выбираем метод (нативный или pdoTools), продумываем кэширование.
  3. Реализация: пишем PHP-код сниппета и чанки шаблонов.
  4. Тестирование: проверяем на крайних значениях (пустые категории, 0 записей), замеряем время выполнения.
  5. Деплой: размещаем на боевом сервере, настраиваем кэш, даём документацию по вызову.

Сроки и стоимость

Сроки: от 0,5 дня для простого сниппета до 5 дней для сложного с интеграцией API. Точную оценку даём после знакомства с проектом. Стоимость рассчитывается индивидуально.

Свяжитесь с нами для обсуждения вашего проекта. Закажите разработку сниппета прямо сейчас — получите быстрый и безопасный код. Опыт разработки под MODX — более 5 лет. Пишите, и мы оценим задачу и предложим оптимальное решение.

Наши компетенции:

Последние работы

  • Разработка сайта компании B2B ADVANCE
    Разработка сайта компании B2B ADVANCE
    1542
  • Разработка веб-приложения для компании FEEDME
    Разработка веб-приложения для компании FEEDME
    1393
  • Разработка веб-сайта для компании БЕЛФИНГРУПП
    Разработка веб-сайта для компании БЕЛФИНГРУПП
    1081
  • Разработка интернет магазина для компании FURNORO
    Разработка интернет магазина для компании FURNORO
    1368
  • Разработка веб-приложения для компании Enviok
    Разработка веб-приложения для компании Enviok
    1139
  • Разработка веб-сайта для компании ФИКСПЕР
    Разработка веб-сайта для компании ФИКСПЕР
    1060