📸 Eigenes pThumb-Snippet
Eigenes pThumb-Snippet für MODX 3.1.x+ und PHP 8.2+
pThumb ist eine moderne Weiterentwicklung von phpThumbOf mit besserem Caching-Mechanismus.
In Templates / Chunks verwendest du z.B.:
[[!pthumb? &input=`assets/images/meinbild.jpg` &options=`w=300&h=200&zc=1`]]
Leider wird pThumb faktisch seit Jahren nicht mehr wirklich gepflegt.
Also bauen wir unser eigenes pthumb Snippet, das die gewohnte Syntax beibehält.
✅ Kompatibilität
- MODX 3.1.x+
- PHP 8.2+
💡 Idee
Du ersetzt den alten pThumb-Snippet-Eintrag im Manager durch ein eigenes Snippet mit demselben Namen.
Dieses neue Snippet verwendet direkt die in MODX integrierte modPhpThumb-Klasse (Namespace MODX\Revolution), die unter MODX 3 aktiv gepflegt wird und PHP-8-kompatibel ist.
So bleiben alle bestehenden Aufrufe weiterhin funktionsfähig, zum Beispiel:
[[!pthumb? &input=`assets/images/meinbild.png` &options=`w=300&h=200&zc=1`]]
Du musst also weder Templates noch Inhalte ändern.
Gleichzeitig stellt deine angepasste Version sicher:
- PNG- und GIF-Bilder behalten ihre Transparenz (Alpha)
- das Ausgabeformat bleibt standardmäßig beim Original (außer du setzt explizit
f=jpg,f=png, … in&options) - Thumbnails werden wie gewohnt skaliert (
w,h,zc) - Probleme durch alte Thumbnails lassen sich einfach beheben, indem du den Cache-Ordner
assets/images-cache/leerst
Hinweis:
Wenn dein Snippet das alte phpthumbof ersetzen soll, muss es ebenfalls phpthumbof heißen.
Du musst sonst nichts weiter beachten, außer dass du dann genau diesen Namen in Templates oder Chunks aufrufst.
Es ist auch möglich, beide Varianten parallel zu nutzen: ein Snippet pthumb und zusätzlich ein Snippet phpthumbof.
🛠️ Beispiel-Snippet pthumb (Basis-Drop-In)
In MODX einen neuen Snippet mit dem Namen pthumb anlegen
(Inhalt z.B. so, Pfadnamen kannst du bei Bedarf anpassen):
<?php
/**
* pthumb (eigener Ersatz für das alte pThumb / phpThumbOf)
* V 2025-12-05
*
* Hinweis:
* Wenn dieses Snippet das alte "phpthumbof" ersetzen soll, muss es auch
* "phpthumbof" heißen. Alternativ können beide parallel existieren
* (pthumb + phpthumbof).
*
* Ziel:
* [[!pthumb? &input=`assets/images/meinbild.jpg` &options=`w=300&h=200&zc=1`]]
* -> gibt eine Thumbnail-URL zurück (exakt 300x200, mit Beschnitt)
*
* Beispiel ohne Beschnitt, Seitenverhältnis bleibt erhalten:
* [[!pthumb? &input=`assets/images/meinbild.jpg` &options=`w=300`]]
* -> verkleinert proportional auf 300px Breite (Höhe wird automatisch berechnet)
*
* Transparenz / Ausgabeformat:
* - PNG-, GIF- und WebP-Quellen bleiben standardmäßig in ihrem Format,
* damit Alpha-Transparenz erhalten bleibt.
* - Das Ausgabeformat kann explizit über &options (`f=jpg`, `f=png`, ...) geändert werden.
* - JPEG-Quellen bleiben standardmäßig JPEG.
*
* Voraussetzungen:
* - MODX 3.1.x oder höher
* - PHP 8.1.x oder höher
*/
use MODX\Revolution\modPhpThumb;
$input = $modx->getOption('input', $scriptProperties, '');
$optionsString = $modx->getOption('options', $scriptProperties, '');
$toPlaceholder = $modx->getOption('toPlaceholder', $scriptProperties, '');
// lokaler Pfad
$cacheDir = $modx->getOption('pthumb_cache_path', $scriptProperties, 'assets/images-cache');
// nichts zu tun
if ($input === '') {
return '';
}
// Basispfade
$basePath = MODX_BASE_PATH;
$baseUrl = $modx->getOption('base_url', null, '/');
$cacheDirTrim = trim($cacheDir, '/');
// CacheManager holen (für writeTree)
$cacheManager = $modx->getCacheManager();
// Optionsstring etwas normalisieren (& -> &)
$optionsNormalized = str_replace('&', '&', $optionsString);
// Optionen in Array parsen (einfach, ohne Arrays wie fltr[])
$params = [];
if ($optionsNormalized !== '') {
$pairs = explode('&', $optionsNormalized);
foreach ($pairs as $pair) {
if ($pair === '') {
continue;
}
$kv = explode('=', $pair, 2);
$key = $kv[0];
$val = $kv[1] ?? '';
$params[$key] = $val;
}
}
// Quelldatei auf Dateisystempfad abbilden
$src = $input;
// Relativer Pfad -> an BASE_PATH hängen
$srcFs = $basePath . ltrim($input, '/');
$src = $srcFs;
if (is_file($srcFs)) {
$mtime = filemtime($srcFs) ?: 0;
} else {
$mtime = 0;
$modx->log(modX::LOG_LEVEL_ERROR, '[pthumb] Quelldatei nicht gefunden: ' . $srcFs);
// Fallback: Original-URL zurückgeben
return $input;
}
// Dateiendung bestimmen
$pathInfo = pathinfo($input);
$ext = strtolower($pathInfo['extension'] ?? '');
$outputExt = $ext;
/**
* Transparenz erhalten:
* Wenn Quellbild PNG/GIF/WebP ist und kein Ausgabeformat vorgegeben wurde
* (weder f= noch fm=), erzwingen wir dasselbe Format als Ausgabeformat.
*/
if (in_array($ext, ['png', 'gif', 'webp'], true)
&& empty($params['f'])
&& empty($params['fm'])) {
$params['f'] = $outputExt = $ext;
}
// pThumb/phpThumbOf-Kompatibilität: f= / fm= ändern das Ausgabeformat
if (!empty($params['f'])) {
$outputExt = strtolower($params['f']);
}
if (!empty($params['fm'])) {
$outputExt = strtolower($params['fm']);
}
// Cache-Dateinamen erzeugen (ähnliche Idee wie pThumb: originaler Name + Hash)
// $hash = md5($input . '|' . $optionsNormalized);
$hash = md5($input . '|' . $optionsNormalized . '|' . $mtime);
$relativeDir = ltrim($pathInfo['dirname'] ?? '', './\\');
$relativeDir = ($relativeDir === '' || $relativeDir === '.') ? '' : $relativeDir . '/';
$cacheFileName = $pathInfo['filename'] . '.' . $hash . '.' . $outputExt;
$cacheRelPath = $cacheDirTrim . '/' . $relativeDir . $cacheFileName;
$cacheAbsPath = $basePath . $cacheRelPath;
$cacheUrl = $baseUrl . $cacheRelPath;
// Wenn Thumbnail schon existiert -> direkt ausgeben
if (is_file($cacheAbsPath)) {
if ($toPlaceholder !== '') {
$modx->setPlaceholder($toPlaceholder, $cacheUrl);
if (!empty($params['w'])) {
$modx->setPlaceholder($toPlaceholder . '.width', (int)$params['w']);
}
if (!empty($params['h'])) {
$modx->setPlaceholder($toPlaceholder . '.height', (int)$params['h']);
}
return '';
}
return $cacheUrl;
}
// Thumbnail über modPhpThumb erzeugen
try {
$phpThumb = new modPhpThumb($modx);
} catch (\Throwable $e) {
// Fallback: originalen Pfad zurückgeben
$modx->log(modX::LOG_LEVEL_ERROR, '[pthumb] Konnte modPhpThumb nicht instanzieren: ' . $e->getMessage());
return $input;
}
$phpThumb->initialize();
$phpThumb->set($src);
// alle bekannten Parameter durchreichen
foreach ($params as $key => $value) {
if ($key === '' || $value === '') {
continue;
}
if ($key === 'fm') {
$phpThumb->setParameter('f', $value);
} else {
$phpThumb->setParameter($key, $value);
}
}
// Zielverzeichnis anlegen
$cacheManager->writeTree(dirname($cacheAbsPath) . '/');
// Thumbnail erzeugen und speichern
if ($phpThumb->GenerateThumbnail()) {
if ($phpThumb->RenderToFile($cacheAbsPath)) {
if ($toPlaceholder !== '') {
$modx->setPlaceholder($toPlaceholder, $cacheUrl);
if (!empty($params['w'])) {
$modx->setPlaceholder($toPlaceholder . '.width', (int)$params['w']);
}
if (!empty($params['h'])) {
$modx->setPlaceholder($toPlaceholder . '.height', (int)$params['h']);
}
return '';
}
return $cacheUrl;
} else {
$modx->log(modX::LOG_LEVEL_ERROR, '[pthumb] RenderToFile() fehlgeschlagen für ' . $cacheAbsPath);
}
} else {
$modx->log(modX::LOG_LEVEL_ERROR, '[pthumb] GenerateThumbnail() fehlgeschlagen für ' . $src);
}
// Im Fehlerfall: originalen Pfad zurückgeben
return $input;
📄 Verwendung im Template / in Chunks
Einfaches Beispiel:
<img src="[[!pthumb? &input=`assets/images/meinbild.jpg` &options=`w=300&h=200&zc=1`]]" alt="">
Mit Platzhaltern:
[[!pthumb?
&input=`[[+tv.image]]`
&options=`w=300&h=200`
&toPlaceholder=`thumb`
]]
<img src="[[+thumb]]" width="[[+thumb.width]]" height="[[+thumb.height]]" alt="">
⚠️ Wichtige Hinweise / Grenzen
🔧 Snippet-Name
- Wenn das alte pThumb-Extra noch installiert ist, gibt es vermutlich schon ein Snippet
pthumb. - Das musst du löschen oder umbenennen, bevor du dein eigenes
pthumbanlegst, sonst gibt es Konflikte.
🧩 Kompatibilität
- Standardoptionen wie
w,h,zc,q,fundfmfunktionieren vollständig mit dem Snippet. - Komplexere Filter wie
fltr[]=stc|ffffffwerden im aktuellen Beispiel nicht speziell verarbeitet. - Wenn du solche erweiterten Filter intensiv benötigst, müsste die Options-Parsing-Logik entsprechend erweitert werden.
📁 Cache-Pfad
- Aktuell:
assets/images-cache/... - Kannst du über die Snippet-Property
pthumb_cache_pathanpassen, wenn du einen anderen Pfad brauchst (z.B. um eine alte pThumb-Cache-Struktur nachzubauen).
🧱 MODX-/PHP-Stand
- MODX 3.1.x ist offiziell mit PHP 8.2 getestet.
modPhpThumbist Teil des Cores und wird mitgepflegt, also deutlich zukunftssicherer als das alte pThumb-Extra.
Damit kannst du deine bestehenden Aufrufe von [[!pthumb? ...]] weiter benutzen, ohne alle Chunks/Template-Codes anfassen zu müssen.
🖼️ Wie Bilder mit GD gecached werden
GD selbst erstellt keinen Cache, sondern verarbeitet nur das Bild (laden, skalieren, speichern).
Der eigentliche Cache entsteht durch das Speichern des erzeugten Thumbnails auf der Festplatte.
Ablauf:
- Beim ersten Aufruf wird das Bild über GD verarbeitet
- Das Snippet speichert das fertige Thumbnail unter:
assets/images-cache/... - Beim nächsten Aufruf prüft das Snippet:
Wenn die Datei bereits existiert → direkt zurückgeben, kein GD mehr nötig
Damit verbraucht nur der erste Aufruf CPU, alle weiteren nutzen die gespeicherte Thumbnail-Datei als Cache.
✅ Ergebnis
bs5GalleryModalbleibt unverändert- Thumbnails werden über
pthumbgecached - Cache liegt in
assets/images-cache/und kann bei Bedarf bedenkenlos gelöscht werden