fix: Bildauswahl nach Dolibarr-Galerie-Reihenfolge (Position/Cover) statt alphabetisch [deploy]
All checks were successful
Deploy ProductImageTags / deploy (push) Successful in 9s

Bilder wurden bisher rein alphabetisch nach Dateiname sortiert — dadurch
landete ein willkürliches Bild im Angebot, nicht das, was in der
Produktgalerie als erstes/Hauptbild festgelegt ist.

listSourceImages liest jetzt position + cover aus llx_ecm_files und
sortiert exakt wie Product::show_photos(): Cover zuerst, dann
Galerie-Position (Dokumente-Tab → Reihenfolge per Pfeile/Drag&Drop),
dann alphabetisch als Fallback. Nicht indexierte Dateien ans Ende.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Eduard Wisch 2026-06-18 17:49:21 +02:00
parent 8cd8ec58ab
commit 6b74300233
2 changed files with 57 additions and 4 deletions

View file

@ -1,5 +1,17 @@
# Changelog — ProductImageTags
## 0.1.1 (2026-06-18)
### Behoben
- **Falsches Produktbild im Angebot.** Bilder wurden rein alphabetisch nach Dateiname
sortiert, dadurch landete „das erste Bild" willkürlich im PDF — nicht das, was im
Produktkärtchen als Hauptbild/erstes Bild angezeigt wird. `listSourceImages` liest
jetzt `position` und `cover` aus `llx_ecm_files` und sortiert exakt wie Dolibarrs
`Product::show_photos()`: Cover (Hauptbild) zuerst, dann Galerie-Position, dann
alphabetisch als Fallback. Nicht indexierte Dateien landen am Ende (Position 999999).
→ Hauptbild per Drag&Drop an Position 1 ziehen oder als Cover markieren steuert jetzt,
welches Bild im Angebot erscheint.
## 0.1.0 (2026-04-24)
Erste lauffähige Version — Bilder erscheinen live in Angebots-/Auftrags-PDFs.

View file

@ -167,18 +167,59 @@ class ProductImage
return array();
}
// dol_dir_list sortiert stabil alphabetisch. Thumbnails (thumbs-Unterordner + _small/_mini-Suffixe) ausschließen.
// Thumbnails (thumbs-Unterordner + _small/_mini-Suffixe) ausschließen.
$files = dol_dir_list($photoDir, 'files', 0, '', array('\.meta$', '_small\.', '_mini\.', '_preview'), 'name', SORT_ASC);
if (empty($files)) {
return array();
}
$result = array();
// WICHTIG: Reihenfolge GENAU wie Dolibarr im Produktkärtchen (Product::show_photos
// sortiert nach position_name + cover aus der Tabelle ecm_files). Sortieren wir nur
// alphabetisch nach Dateiname, ist „das erste Bild" willkürlich und passt nicht zu
// dem, was der User als Hauptbild/erste Reihenfolge in der Bildergalerie sieht.
// Deshalb Position + Cover aus ecm_files lesen und danach sortieren:
// 1. Cover (manuell als Hauptbild markiert) zuerst
// 2. dann Position (per Drag&Drop in der Galerie festgelegt)
// 3. dann alphabetisch als Fallback (nicht indexierte Dateien ans Ende)
$relativedir = trim(preg_replace('#^'.preg_quote(DOL_DATA_ROOT, '#').'#', '', $photoDir), '/\\');
$meta = array();
$dbfiles = dol_dir_list_in_database($relativedir, '', null, 'name', SORT_ASC, 0, '', $product);
foreach ($dbfiles as $dbf) {
$meta[$dbf['name']] = array(
'position' => (int) $dbf['position'],
'cover' => (int) $dbf['cover'],
);
}
$indexed = array();
foreach ($files as $file) {
$fullPath = $file['fullname'];
if (image_format_supported($fullPath) > 0) {
$result[] = $fullPath;
if (image_format_supported($fullPath) <= 0) {
continue;
}
$name = $file['name'];
$indexed[] = array(
'path' => $fullPath,
'name' => $name,
'cover' => isset($meta[$name]) ? $meta[$name]['cover'] : 0,
// Nicht indexierte Dateien ans Ende (Dolibarr-Konvention: position 999999)
'position' => isset($meta[$name]) ? $meta[$name]['position'] : 999999,
);
}
usort($indexed, function ($a, $b) {
if ($a['cover'] !== $b['cover']) {
return $b['cover'] - $a['cover']; // cover=1 zuerst
}
if ($a['position'] !== $b['position']) {
return $a['position'] - $b['position'];
}
return strcasecmp($a['name'], $b['name']);
});
$result = array();
foreach ($indexed as $row) {
$result[] = $row['path'];
}
return $result;
}