MODX Custom Snippet Development
A MODX snippet is PHP code returning a string for output in template. It's the main tool for dynamic functionality: product lists, filters, API integrations, calculations. Snippet receives parameters from template and returns HTML.
Snippet Structure
<?php
// Snippet ProductList
// Call: [[!ProductList? &category=`5` &limit=`12` &sort=`price`]]
// Get parameters (with defaults)
$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';
// Query resources via MODX API
$c = $modx->newQuery('modResource');
$c->where([
'parent' => $categoryId,
'published' => 1,
'deleted' => 0,
'class_key' => 'modDocument',
]);
// Get TV values via 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'),
]);
// Chunk for card output
$output .= $modx->getChunk($tpl, $data);
}
return $output;
Snippet with pdoTools (Recommended)
pdoTools provides pdoFetch — fast and correct way to make queries:
<?php
// Snippet ProductSearch with pdoTools
if (!$modx->loadClass('pdoFetch', MODX_CORE_PATH . 'components/pdotools/model/pdotools/', false, true)) {
return 'pdoTools not installed';
}
$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;
Snippet with Caching
<?php
// Cache result for 30 minutes
$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;
// ... query ...
$output = generateOutput($resources);
$modx->cacheManager->set($cacheKey, $output, 1800, $cacheOptions);
return $output;
Snippet for External API Integration
<?php
// Snippet WeatherWidget — weather from 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=en";
$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);
Passing Parameters to Snippet
[[!ProductList?
&category=`[[*id]]`
&limit=`12`
&tpl=`productCardTpl`
&sort=`price`
&sortdir=`ASC`
]]
! before name — uncached call (dynamic content).
Without ! — cached (static block, same for all).
Timeline
Developing one snippet with resource query, caching and chunk output — 0.5–2 days. Complex snippet with filters, pagination and API integration — 3–5 days.







