DataFirefly Image Optimizer — Documentation Shopware 6
Installation, configuration WebP/AVIF, intégration CDN, API Twig et dépannage du plugin Image Optimizer pour Shopware 6.6 et 6.7.
DataFirefly Image Optimizer transforme automatiquement chaque image média Shopware en variantes WebP et AVIF, recompresse les JPEG et PNG d’origine, et réécrit les URLs vers votre CDN — sans modification de thème. Cette documentation couvre l’installation, la configuration complète, l’API Twig exposée aux thèmes, et le dépannage.
Installation
Le plugin est livré sous forme de ZIP. Deux méthodes d’installation, équivalentes fonctionnellement.
Via l’administration Shopware
- Réglages → Système → Extensions → Téléverser une extension
- Sélectionnez
DfImageOptimizer-1.0.0.zip - Cliquez sur Installer puis Activer
- Vider le cache : Réglages → Système → Cache & Index → Vider
Via CLI (recommandé)
cd /chemin/vers/shopware
unzip DfImageOptimizer-1.0.0.zip -d custom/plugins/
sudo -u www-data setsid php bin/console plugin:refresh
sudo -u www-data setsid php bin/console plugin:install --activate DfImageOptimizer
sudo -u www-data setsid php bin/console cache:clear
sudo -u www-data setsid php bin/console theme:compile
theme:compile est obligatoire après installation pour que l’override Twig du composant thumbnail soit actif sur le storefront. Sans cette étape, les balises <picture> ne seront pas générées même si WebP et AVIF sont produits.Vérification post-installation
Allez dans le menu admin Catalogues → Image Optimizer. Le dashboard doit s’afficher avec une carte Compatibilité serveur indiquant en temps réel :
- Version PHP détectée (8.2 minimum)
- Présence d’Imagick (recommandé)
- Présence de GD (obligatoire)
- Support effectif WebP — doit être ✓
- Support effectif AVIF — peut être ✗ selon le serveur, pas bloquant
- Moteur recommandé : Imagick ou GD
Architecture en deux mots
Quand une image est uploadée, le plugin écoute l’événement entity media.written, charge l’image dans un fichier temporaire local, puis produit en parallèle :
- L’original recompressé (remplace le fichier d’origine si Compresser original est coché)
- Un sibling WebP à côté avec extension cumulée :
foo.jpg→foo.jpg.webp - Un sibling AVIF à côté :
foo.jpg→foo.jpg.avif
Les vignettes Shopware générées par le ThumbnailService natif sont traitées de la même manière. Côté storefront, l’override Twig de storefront/component/image/thumbnail.html.twig wrappe la balise <img> dans un <picture> avec sources AVIF, WebP, et fallback original — le navigateur choisit automatiquement le format le plus léger qu’il supporte.
Configuration
Accès : Réglages → Système → Extensions → DfImageOptimizer → Configurer. Sept cartes regroupent les options.
Carte « Général »
| Option | Défaut | Effet |
|---|---|---|
| Auto-optimisation à l’upload | Activé | Déclenche le pipeline immédiatement à chaque upload. Désactivez si vous préférez tout faire en arrière-plan via le cron. |
| Traiter les vignettes | Activé | Génère WebP/AVIF aussi pour les vignettes Shopware (typiquement 4 à 6 tailles par image source). |
Carte « WebP »
| Option | Défaut | Recommandation |
|---|---|---|
| Activer WebP | Activé | À garder activé sauf cas très spécifique. WebP est supporté par 96 % des navigateurs. |
| Qualité WebP (1-100) | 82 | 75-85 pour un bon compromis. 90+ pour photographie haut de gamme, 70 pour catalogue volumineux. |
| Lossless pour PNG | Désactivé | Activez seulement si vos PNG contiennent du texte ou des graphiques nets (logos, icônes). Sinon le mode lossy donne de meilleurs gains. |
Carte « AVIF »
| Option | Défaut | Recommandation |
|---|---|---|
| Activer AVIF | Désactivé | Activez si le dashboard indique que votre serveur supporte AVIF. Gain typique de 50 % vs JPEG, mais encodage plus lent que WebP. |
| Qualité AVIF (1-100) | 55 | 45-65 pour un excellent rendu. AVIF tolère des qualités plus basses que JPEG/WebP grâce à son codec moderne. |
| Largeur max pour AVIF (px) | 2400 | Garde-fou CPU. Les images au-delà sont sautées pour AVIF mais conservent leur WebP. Augmentez si vous avez un serveur puissant et besoin d’AVIF sur grandes images. |
IMG_AVIF compilé, soit Imagick avec libheif. Le dashboard Compatibilité serveur vous indique exactement ce qui est disponible. Si AVIF n’est pas supporté, l’option reste inopérante même cochée — pas d’erreur, juste pas de génération AVIF.Carte « Compression »
| Option | Défaut | Recommandation |
|---|---|---|
| Compresser les JPG/PNG originaux | Activé | Remplace l’original par sa version recompressée. Action irréversible — désactivez si vous voulez conserver les sources brutes pour des retouches futures. |
| Qualité JPEG (1-100) | 85 | 85 est le standard photo web. Descendre à 80 pour gain supplémentaire si la qualité reste acceptable visuellement. |
| Niveau de compression PNG (0-9) | 7 | 9 = compression maximale mais 3-4× plus lente. 7 est l’équilibre standard. |
| Supprimer les métadonnées EXIF/ICC | Activé | Gain typique 5 à 30 Ko par photo issue d’appareil. Conservez si vous gérez du contenu nécessitant des profils colorimétriques précis. |
Carte « CDN »
| Option | Défaut | Explication |
|---|---|---|
| Activer la réécriture CDN | Désactivé | Si désactivé, les URLs pointent vers votre origine. Activez après avoir configuré votre CDN. |
| URL de base du CDN | — | Format : https://cdn.exemple.com sans slash final. Ex : https://shop-cdn.b-cdn.net pour BunnyCDN. |
| Portée de réécriture | Médias uniquement | Voir détail ci-dessous. |
| Conserver les query strings | Activé | Préserve les paramètres de cache-busting (?v=1234) lors de la réécriture. |
Détail des trois portées :
- Médias uniquement — réécrit uniquement les URLs commençant par
/media/. C’est le plus sûr et couvre 95 % des cas d’usage typiques. - Médias + vignettes — ajoute
/thumbnail/. Utile si votre storefront sert beaucoup de vignettes générées dynamiquement. - Tous les assets statiques — ajoute
/theme/,/bundles/et/assets/. Ne choisissez cette option que si votre CDN est correctement configuré pour pull-cache tous les assets et que vous avez testé en staging.
Carte « Rendu frontend »
| Option | Défaut | Effet |
|---|---|---|
Sortie en balise <picture> |
Activé | Wrappe les <img> du storefront dans un <picture> avec sources AVIF/WebP. |
Ajouter loading="lazy" |
Activé | Lazy-loading natif navigateur. À conserver sauf si vous avez votre propre solution. |
Ajouter decoding="async" |
Activé | Permet au navigateur de décoder en parallèle du parsing HTML. |
Forcer width/height |
Activé | Anti-CLS (Cumulative Layout Shift). Le navigateur réserve la place du visuel avant son chargement. |
Carte « Traitement en lot »
| Option | Défaut | Recommandation |
|---|---|---|
| Taille de lot pour la tâche cron | 50 | 50 est un bon équilibre. Montez à 100-200 si vous avez besoin de rattraper un gros catalogue rapidement et que votre serveur tient. |
| Intervalle cron (minutes) | 15 | Information seule — l’intervalle réel est défini par la classe OptimizeImagesTask::getDefaultInterval(). Pour changer effectivement, modifiez la valeur dans la table scheduled_task ou réinstallez le plugin après modification. |
Configurer un CDN — exemples concrets
BunnyCDN (recommandé)
- Créez une Pull Zone sur bunny.net avec votre URL d’origine, par exemple
https://shop.exemple.com - BunnyCDN vous donne un hostname du type
shop-cdn.b-cdn.net - Dans la config du plugin, mettez :
https://shop-cdn.b-cdn.net - Choisissez la portée Médias uniquement pour démarrer
- Activez la réécriture CDN
Le plugin injecte automatiquement <link rel="dns-prefetch" href="https://shop-cdn.b-cdn.net"> et <link rel="preconnect" href="https://shop-cdn.b-cdn.net" crossorigin> dans le <head> du storefront — gain de 50 à 200 ms sur la première requête CDN.
Cloudflare
Cloudflare en mode proxy DNS standard ne nécessite pas de réécriture CDN — Cloudflare cache automatiquement sur votre hostname principal. Mais si vous utilisez un Custom Hostname Cloudflare dédié pour les assets (par exemple cdn.exemple.com), configurez-le ici. Activez aussi Cache Reserve ou Polish côté Cloudflare pour bénéficier en plus de l’optimisation Cloudflare par-dessus la vôtre.
KeyCDN
Configuration identique à BunnyCDN : créez une Pull Zone, récupérez l’URL du type shop-12345.kxcdn.com, configurez-la dans le plugin avec le préfixe https://.
AWS CloudFront
Créez une distribution CloudFront avec votre serveur Shopware comme origine. L’URL de distribution est du type https://d1234abc.cloudfront.net — ou votre domaine personnalisé si vous avez configuré un alias. Configurez le TTL minimum à 1 jour pour profiter pleinement du cache.
Pipeline d’optimisation détaillé
Pour chaque image (originale ou vignette) à traiter, le plugin exécute les étapes suivantes dans l’ordre :
- Téléchargement de l’image source depuis le filesystem public Shopware vers un fichier temporaire local (
/tmp/dfimgopt_xxx.jpg) - Si Compresser original activé : recompression in-place avec qualité configurée, suppression métadonnées si activé. Si la version recompressée est plus petite que l’originale, elle remplace le fichier d’origine sur le filesystem.
- Si WebP activé : conversion vers WebP, écriture du sibling
foo.jpg.webpsur le filesystem public - Si AVIF activé et largeur ≤ largeur max : conversion vers AVIF, écriture du sibling
foo.jpg.avif - Enregistrement dans la table
df_image_optimizeravec compteurs et taille économisée - Nettoyage du fichier temporaire local via bloc
finally(même en cas d’erreur)
Imagick est utilisé en priorité quand disponible (qualité supérieure et seul moteur AVIF via libheif sur de nombreux serveurs). GD prend le relais sinon — il supporte WebP depuis longtemps et AVIF depuis PHP 8.1.
Tâche planifiée — rattrapage des images existantes
Activer le plugin sur une boutique avec déjà des milliers d’images en base ne déclenche pas l’optimisation rétroactive. C’est intentionnel : convertir 50 000 images en AVIF d’un coup saturerait votre serveur. À la place, la tâche planifiée df_image_optimizer.optimize_pending s’exécute toutes les 15 minutes par défaut :
- Requête SQL via LEFT JOIN sur
df_image_optimizerpour identifier les médias non encore optimisés - Traite un lot de 50 images (taille de lot configurable)
- Termine et libère le worker pour la prochaine tâche
Sur une boutique de 10 000 images, comptez environ 50 heures pour tout rattraper en arrière-plan. Pour accélérer :
- Augmentez la taille de lot dans la config (essayez 100 ou 200)
- Utilisez le bouton Lancer un lot du dashboard plusieurs fois d’affilée
- Exécutez la tâche en boucle manuellement via CLI :
for i in {1..100}; do sudo -u www-data setsid php bin/console scheduled-task:run-single df_image_optimizer.optimize_pending; done
API Twig exposée aux thèmes
Deux helpers Twig sont enregistrés et utilisables dans n’importe quel template de thème ou plugin.
Filtre |df_cdn
Réécrit une URL vers le CDN si activé, sinon retourne l’URL inchangée. Utile pour les assets que vous incluez manuellement.
<img src="{{ media.url|df_cdn }}" alt="...">
<link rel="preload" as="image" href="{{ heroImage.url|df_cdn }}">
<style>
.hero { background-image: url("{{ bgImage.url|df_cdn }}"); }
</style>
Fonction df_picture()
Rend une balise <picture> complète avec sources AVIF, WebP et fallback original, plus tous les attributs configurés (lazy, async, width/height).
{{ df_picture(
media,
alt='Description accessible',
classes='product-image card-img',
sizes='(max-width: 768px) 100vw, 50vw'
) }}
Génère :
<picture>
<source type="image/avif"
srcset="https://cdn.exemple.com/media/foo.jpg.avif"
sizes="(max-width: 768px) 100vw, 50vw">
<source type="image/webp"
srcset="https://cdn.exemple.com/media/foo.jpg.webp"
sizes="(max-width: 768px) 100vw, 50vw">
<img src="https://cdn.exemple.com/media/foo.jpg"
alt="Description accessible"
class="product-image card-img"
sizes="(max-width: 768px) 100vw, 50vw"
loading="lazy"
decoding="async"
width="1200"
height="800">
</picture>
Endpoints API admin
Trois endpoints REST sont disponibles, authentifiés via le Bearer token admin standard.
| Méthode | Route | Description |
|---|---|---|
| GET | /api/_action/df-image-optimizer/stats |
Vue d’ensemble + activité 30j + capacités serveur |
| POST | /api/_action/df-image-optimizer/run-batch |
Lance un lot. Paramètre POST optionnel batchSize (défaut 50, max 500) |
| GET | /api/_action/df-image-optimizer/capabilities |
Détection serveur (Imagick / GD / WebP / AVIF) |
Exemple curl :
TOKEN=$(curl -s -X POST https://shop.exemple.com/api/oauth/token
-H "Content-Type: application/json"
-d '{"grant_type":"password","client_id":"administration","scope":"write","username":"admin","password":"shopware"}'
| jq -r .access_token)
curl -X POST https://shop.exemple.com/api/_action/df-image-optimizer/run-batch
-H "Authorization: Bearer $TOKEN"
-H "Content-Type: application/json"
-d '{"batchSize":200}'
Tables créées
df_image_optimizer
Une ligne par média optimisé. Clé unique sur media_id — une nouvelle optimisation du même média écrase la ligne.
id BINARY(16) UUID
media_id BINARY(16) FK media.id ON DELETE CASCADE, UNIQUE
has_webp TINYINT(1)
has_avif TINYINT(1)
compressed TINYINT(1)
original_size BIGINT Poids original en octets
bytes_saved BIGINT Cumul économies (compression + delta WebP/AVIF)
sales_channel_id BINARY(16) FK sales_channel.id ON DELETE SET NULL
optimized_at DATETIME(3)
created_at DATETIME(3)
df_image_optimizer_log
Journal optionnel des erreurs. Lecture seule pour le debug — pas de purge automatique.
Dépannage
« Le dashboard affiche AVIF : Indisponible »
Votre serveur n’a pas la stack AVIF requise. Options :
- Si GD-only : vérifiez
php -m | grep gdetphp -i | grep AVIF. Il faut PHP 8.1+ et GD compilé avec--with-avif. Sur Debian/Ubuntu récents, c’est par défaut. - Si Imagick disponible : vérifiez
php -r "print_r(Imagick::queryFormats('AVIF'));". Vide ? Votre Imagick n’est pas compilé avec libheif — recompilation nécessaire ou passage à GD. - Fallback acceptable : laissez AVIF désactivé et concentrez-vous sur WebP. Le gain de WebP seul est déjà énorme par rapport au JPEG natif Shopware.
« Les images .webp sont bien générées mais le storefront affiche du JPEG »
Le compilateur de thème n’a pas pris en compte l’override Twig. Solution :
sudo -u www-data setsid php bin/console theme:compile
sudo -u www-data setsid php bin/console cache:clear
Vérifiez ensuite avec les DevTools du navigateur (Chrome ou Firefox) : ouvrez l’onglet Réseau, rechargez une page produit, et regardez le type MIME des images chargées. Vous devriez voir image/avif ou image/webp au lieu de image/jpeg.
« L’upload des médias est devenu lent »
La conversion AVIF en particulier est CPU-intensive — comptez 1 à 3 secondes par image. Si c’est gênant, désactivez l’auto-optimisation à l’upload (carte Général) et laissez uniquement la tâche planifiée traiter en arrière-plan. Les uploads redeviennent instantanés et les images sont optimisées sous 15 minutes max.
« Les vignettes .webp ne sont pas générées »
Vérifiez que Traiter les vignettes est coché dans la carte Général. Régénérez ensuite manuellement les vignettes pour qu’elles repassent dans le pipeline :
sudo -u www-data setsid php bin/console media:generate-thumbnails
« Comment vider tous les fichiers WebP/AVIF générés ? »
Le plugin ne les supprime pas automatiquement, même à la désinstallation (pour préserver vos sauvegardes). Pour les nettoyer manuellement :
cd /chemin/vers/shopware
find public/media -name "*.webp" -delete
find public/media -name "*.avif" -delete
« Les URLs CDN ne sont pas appliquées partout »
Vérifiez la portée configurée. Si vous voyez des URLs origine pour des assets de thème (/theme/.../style.css), c’est normal avec la portée par défaut Médias uniquement. Passez à Tous les assets statiques si votre CDN est configuré pour servir tous les assets.
Notez aussi que les URLs réécrites concernent le rendu Twig serveur. Si votre frontend appelle l’API Store-API et reconstruit les URLs côté JS, vous devrez appliquer la réécriture côté client séparément.
Désinstallation
sudo -u www-data setsid php bin/console plugin:uninstall DfImageOptimizer
sudo -u www-data setsid php bin/console plugin:remove DfImageOptimizer
Lors de la désinstallation, Shopware demande si vous voulez conserver les données utilisateur :
- Conserver (par défaut) : les tables
df_image_optimizeretdf_image_optimizer_logrestent en base. Réinstaller le plugin reprendra l’historique. - Ne pas conserver : les deux tables sont supprimées (DROP TABLE).
Dans les deux cas, les fichiers .webp et .avif sur le filesystem restent — utilisez les commandes find ci-dessus pour les nettoyer si nécessaire.
Pour aller plus loin
- Surveillez votre score Core Web Vitals dans Google Search Console — le LCP doit baisser dans les 2 à 4 semaines suivant l’activation
- Testez avec PageSpeed Insights avant/après — gain typique 20 à 40 points sur mobile
- Activez aussi un outil HTTP/2 ou HTTP/3 côté serveur pour multiplier le bénéfice du CDN
- Combinez avec un cache plein page Shopware pour des temps de réponse statiques