# DataFirefly Image Optimizer — Documentation Shopware 6

> 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…

- Page: <https://www.datafirefly.com/documentation/dfimageoptimizer/>
- Langue: fr
- Mis à jour le: 2026-06-29
- Autres langues: [en](https://www.datafirefly.com/en/documentation/dfimageoptimizer/index.md), [es](https://www.datafirefly.com/es/documentation/dfimageoptimizer/index.md), [de](https://www.datafirefly.com/de/documentation/dfimageoptimizer/index.md), [it](https://www.datafirefly.com/it/documentation/dfimageoptimizer/index.md), [pl](https://www.datafirefly.com/pl/documentation/dfimageoptimizer/index.md), [nl](https://www.datafirefly.com/nl/documentation/dfimageoptimizer/index.md), [pt](https://www.datafirefly.com/pt/documentation/dfimageoptimizer/index.md)
- Index: <https://www.datafirefly.com/documentation/llms.txt>

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

1. Réglages → Système → Extensions → Téléverser une extension
2. Sélectionnez `DfImageOptimizer-1.0.0.zip`
3. Cliquez sur Installer puis Activer
4. 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
```

**Astuce.** `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 `` 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 `` dans un `` 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. |

**À propos d'AVIF.** L'encodage AVIF nécessite soit PHP 8.1+ avec le flag `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 `` | Activé | Wrappe les `` du storefront dans un `` 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é)

1. Créez une _Pull Zone_ sur bunny.net avec votre URL d'origine, par exemple `https://shop.exemple.com`
2. BunnyCDN vous donne un hostname du type `shop-cdn.b-cdn.net`
3. Dans la config du plugin, mettez : `https://shop-cdn.b-cdn.net`
4. Choisissez la portée _Médias uniquement_ pour démarrer
5. Activez la réécriture CDN

Le plugin injecte automatiquement `` et `` dans le `` 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 :

1. Téléchargement de l'image source depuis le filesystem public Shopware vers un fichier temporaire local (`/tmp/dfimgopt_xxx.jpg`)
2. **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.
3. **Si WebP activé** : conversion vers WebP, écriture du sibling `foo.jpg.webp` sur le filesystem public
4. **Si AVIF activé et largeur ≤ largeur max** : conversion vers AVIF, écriture du sibling `foo.jpg.avif`
5. Enregistrement dans la table `df_image_optimizer` avec compteurs et taille économisée
6. 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.

**Compression du JPEG original — irréversible.** Quand l'option _Compresser original_ est cochée, la version compressée remplace l'originale sur le filesystem. Si vous avez besoin de retrouver les sources brutes pour d'autres usages (impression, retouches), désactivez cette option — vous garderez quand même les gains via WebP et AVIF.

## 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 :

1. Requête SQL via LEFT JOIN sur `df_image_optimizer` pour identifier les médias non encore optimisés
2. Traite un lot de 50 images (taille de lot configurable)
3. 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 `` 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 gd` et `php -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_optimizer` et `df_image_optimizer_log` restent 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
