# DataFirefly Image Optimizer: dokumentacja Shopware 6

> DataFirefly Image Optimizer automatycznie przekształca każdy obraz media Shopware w warianty WebP i AVIF, ponownie kompresuje oryginalne pliki JPEG i PNG oraz przepisuje adresy URL na Twój CDN, bez modyfikowania…

- Strona: <https://www.datafirefly.com/pl/documentation/dfimageoptimizer/>
- Język: pl
- Zaktualizowano: 2026-07-29
- Inne języki: [fr](https://www.datafirefly.com/documentation/dfimageoptimizer/index.md), [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), [nl](https://www.datafirefly.com/nl/documentation/dfimageoptimizer/index.md), [pt](https://www.datafirefly.com/pt/documentation/dfimageoptimizer/index.md)
- Indeks: <https://www.datafirefly.com/pl/documentation/llms.txt>

DataFirefly Image Optimizer automatycznie przekształca każdy obraz media Shopware w warianty WebP i AVIF, ponownie kompresuje oryginalne pliki JPEG i PNG oraz przepisuje adresy URL na Twój CDN, bez modyfikowania motywu. Ta dokumentacja obejmuje instalację, pełną konfigurację, API Twig udostępniane motywom i rozwiązywanie problemów.

## Instalacja

Plugin jest dostarczany jako ZIP. Dwie metody instalacji, równoważne funkcjonalnie.

### Przez administrację Shopware

1. Ustawienia → System → Rozszerzenia → Prześlij rozszerzenie
2. Wybierz `DfImageOptimizer-1.0.0.zip`
3. Kliknij Zainstaluj, a następnie Aktywuj
4. Wyczyść cache: Ustawienia → System → Cache i indeksy → Wyczyść

### Przez CLI (zalecane)

```
cd /path/to/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
```

**Wskazówka.** `theme:compile` jest obowiązkowe po instalacji, aby override Twig komponentu thumbnail był aktywny w storefroncie. Bez tego kroku znaczniki `` nie będą generowane, nawet jeśli WebP i AVIF powstają.

### Weryfikacja po instalacji

Wejdź w menu administracji **Katalogi → Image Optimizer**. Pulpit powinien się wyświetlić z kartą _Zgodność serwera_ pokazującą w czasie rzeczywistym:

- Wykrytą wersję PHP (minimum 8.2)
- Obecność Imagick (zalecane)
- Obecność GD (obowiązkowe)
- Faktyczne wsparcie WebP, powinno być ✓
- Faktyczne wsparcie AVIF, może być ✗ zależnie od serwera, nie blokuje działania
- Zalecany silnik: Imagick albo GD

## Architektura w dwóch słowach

Gdy obraz jest przesyłany, plugin nasłuchuje zdarzenia encji `media.written`, wczytuje obraz do lokalnego pliku tymczasowego, a następnie równolegle tworzy:

- Ponownie skompresowany oryginał (zastępuje plik źródłowy, jeśli _Kompresuj oryginał_ jest zaznaczone)
- Bliźniaczy plik WebP obok, z kumulowanym rozszerzeniem: `foo.jpg` → `foo.jpg.webp`
- Bliźniaczy plik AVIF obok: `foo.jpg` → `foo.jpg.avif`

Miniatury Shopware generowane przez natywny `ThumbnailService` są przetwarzane tak samo. Po stronie storefrontu override Twig pliku `storefront/component/image/thumbnail.html.twig` opakowuje znacznik `` w `` ze źródłami AVIF, WebP i oryginalnym fallbackiem: przeglądarka automatycznie wybiera najlżejszy format, który obsługuje.

## Konfiguracja

Dostęp: **Ustawienia → System → Rozszerzenia → DfImageOptimizer → Konfiguruj**. Opcje są zebrane w siedmiu kartach.

### Karta "Ogólne"

| Opcja | Domyślnie | Efekt |
| --- | --- | --- |
| Autooptymalizacja przy przesyłaniu | Włączone | Uruchamia pipeline natychmiast przy każdym przesłaniu. Wyłącz, jeśli wolisz robić wszystko w tle przez cron. |
| Przetwarzaj miniatury | Włączone | Generuje WebP/AVIF także dla miniatur Shopware (zwykle od 4 do 6 rozmiarów na obraz źródłowy). |

### Karta "WebP"

| Opcja | Domyślnie | Zalecenie |
| --- | --- | --- |
| Włącz WebP | Włączone | Zostaw włączone poza bardzo specyficznymi przypadkami. WebP jest obsługiwany przez 96% przeglądarek. |
| Jakość WebP (1-100) | 82 | 75-85 to dobry kompromis. 90+ dla fotografii premium, 70 dla bardzo dużych katalogów. |
| Bezstratny dla PNG | Wyłączone | Włącz tylko wtedy, gdy Twoje pliki PNG zawierają tekst albo ostrą grafikę (logotypy, ikony). W przeciwnym razie tryb stratny daje lepsze zyski. |

### Karta "AVIF"

| Opcja | Domyślnie | Zalecenie |
| --- | --- | --- |
| Włącz AVIF | Wyłączone | Włącz, jeśli pulpit wskazuje, że Twój serwer obsługuje AVIF. Typowy zysk 50% wobec JPEG, ale kodowanie wolniejsze niż WebP. |
| Jakość AVIF (1-100) | 55 | 45-65 dla doskonałego efektu. AVIF toleruje niższe jakości niż JPEG/WebP dzięki nowoczesnemu kodekowi. |
| Maksymalna szerokość dla AVIF (px) | 2400 | Zabezpieczenie CPU. Obrazy powyżej są pomijane przy AVIF, ale zachowują swój WebP. Zwiększ, jeśli masz mocny serwer i potrzebujesz AVIF na dużych obrazach. |

**O AVIF.** Kodowanie AVIF wymaga albo PHP 8.1+ ze skompilowaną flagą `IMG_AVIF`, albo Imagick z libheif. Pulpit _Zgodność serwera_ pokazuje dokładnie, co jest dostępne. Jeśli AVIF nie jest obsługiwany, opcja pozostaje bezskuteczna nawet po zaznaczeniu: bez błędu, po prostu bez generowania AVIF.

### Karta "Kompresja"

| Opcja | Domyślnie | Zalecenie |
| --- | --- | --- |
| Kompresuj oryginalne JPG/PNG | Włączone | Zastępuje oryginał wersją ponownie skompresowaną. Działanie **nieodwracalne**: wyłącz, jeśli chcesz zachować surowe źródła do przyszłych retuszy. |
| Jakość JPEG (1-100) | 85 | 85 to standard fotografii webowej. Zejście do 80 daje dodatkowy zysk, jeśli jakość pozostaje wizualnie akceptowalna. |
| Poziom kompresji PNG (0-9) | 7 | 9 = kompresja maksymalna, ale od 3 do 4 razy wolniejsza. 7 to standardowa równowaga. |
| Usuń metadane EXIF/ICC | Włączone | Typowy zysk od 5 do 30 KB na zdjęcie z aparatu. Zachowaj, jeśli obsługujesz treści wymagające precyzyjnych profili kolorystycznych. |

### Karta "CDN"

| Opcja | Domyślnie | Wyjaśnienie |
| --- | --- | --- |
| Włącz przepisywanie na CDN | Wyłączone | Po wyłączeniu adresy URL wskazują na Twój origin. Włącz po skonfigurowaniu CDN. |
| Bazowy adres URL CDN | — | Format: `https://cdn.example.com` bez końcowego ukośnika. Np. `https://shop-cdn.b-cdn.net` dla BunnyCDN. |
| Zakres przepisywania | Tylko media | Szczegóły poniżej. |
| Zachowaj query string | Włączone | Zachowuje parametry cache-bustingu (`?v=1234`) przy przepisywaniu. |

**Szczegóły trzech zakresów:**

- **Tylko media**: przepisuje wyłącznie adresy zaczynające się od `/media/`. Najbezpieczniejsze i pokrywa 95% typowych zastosowań.
- **Media plus miniatury**: dodaje `/thumbnail/`. Przydatne, jeśli Twój storefront serwuje dużo dynamicznie generowanych miniatur.
- **Wszystkie zasoby statyczne**: dodaje `/theme/`, `/bundles/` i `/assets/`. Wybierz tę opcję tylko wtedy, gdy Twój CDN jest poprawnie skonfigurowany do pull-cache wszystkich zasobów i przetestowałeś to na stagingu.

### Karta "Renderowanie frontendu"

| Opcja | Domyślnie | Efekt |
| --- | --- | --- |
| Wyjście jako znacznik `` | Włączone | Opakowuje znaczniki `` storefrontu w `` ze źródłami AVIF/WebP. |
| Dodaj `loading="lazy"` | Włączone | Natywne lazy-loading przeglądarki. Zostaw, chyba że masz własne rozwiązanie. |
| Dodaj `decoding="async"` | Włączone | Pozwala przeglądarce dekodować równolegle z parsowaniem HTML. |
| Wymuś `width`/`height` | Włączone | Ochrona przed CLS (Cumulative Layout Shift). Przeglądarka rezerwuje miejsce na wizualizację przed jej załadowaniem. |

### Karta "Przetwarzanie wsadowe"

| Opcja | Domyślnie | Zalecenie |
| --- | --- | --- |
| Rozmiar partii dla zadania cron | 50 | 50 to dobra równowaga. Podnieś do 100-200, jeśli musisz szybko nadrobić duży katalog, a Twój serwer to wytrzyma. |
| Interwał crona (minuty) | 15 | Tylko informacyjnie: rzeczywisty interwał definiuje klasa `OptimizeImagesTask::getDefaultInterval()`. Aby faktycznie go zmienić, zmodyfikuj wartość w tabeli `scheduled_task` albo zainstaluj plugin ponownie po zmianie. |

## Konfiguracja CDN: konkretne przykłady

### BunnyCDN (zalecane)

1. Utwórz _Pull Zone_ na bunny.net ze swoim adresem origin, na przykład `https://shop.example.com`
2. BunnyCDN daje Ci hostname typu `shop-cdn.b-cdn.net`
3. W konfiguracji pluginu wpisz: `https://shop-cdn.b-cdn.net`
4. Na start wybierz zakres _Tylko media_
5. Włącz przepisywanie na CDN

Plugin automatycznie wstrzykuje `` i `` w sekcji `` storefrontu: zysk od 50 do 200 ms na pierwszym żądaniu do CDN.

### Cloudflare

Cloudflare w standardowym trybie proxy DNS nie wymaga przepisywania na CDN: Cloudflare cache'uje automatycznie na Twoim głównym hostname. Jeśli jednak używasz dedykowanego _Custom Hostname_ Cloudflare dla zasobów (na przykład `cdn.example.com`), skonfiguruj go tutaj. Włącz też _Cache Reserve_ albo _Polish_ po stronie Cloudflare, aby dodatkowo skorzystać z optymalizacji Cloudflare na wierzchu Twojej własnej.

### KeyCDN

Konfiguracja identyczna jak przy BunnyCDN: utwórz Pull Zone, pobierz adres typu `shop-12345.kxcdn.com` i skonfiguruj go w pluginie z prefiksem `https://`.

### AWS CloudFront

Utwórz dystrybucję CloudFront ze swoim serwerem Shopware jako origin. Adres dystrybucji ma postać `https://d1234abc.cloudfront.net` albo Twojej własnej domeny, jeśli skonfigurowano alias. Ustaw minimalny TTL na 1 dzień, aby w pełni korzystać z cache.

## Szczegółowy pipeline optymalizacji

Dla każdego obrazu (oryginału albo miniatury) do przetworzenia plugin wykonuje kolejno następujące kroki:

1. Pobranie obrazu źródłowego z publicznego filesystemu Shopware do lokalnego pliku tymczasowego (`/tmp/dfimgopt_xxx.jpg`)
2. **Jeśli Kompresuj oryginał włączone**: rekompresja w miejscu ze skonfigurowaną jakością, usunięcie metadanych, jeśli włączone. Jeśli wersja ponownie skompresowana jest mniejsza od oryginalnej, zastępuje plik źródłowy na filesystemie.
3. **Jeśli WebP włączone**: konwersja do WebP, zapis bliźniaczego pliku `foo.jpg.webp` na publicznym filesystemie
4. **Jeśli AVIF włączone i szerokość ≤ maksymalna szerokość**: konwersja do AVIF, zapis bliźniaczego pliku `foo.jpg.avif`
5. Zapis w tabeli `df_image_optimizer` z licznikami i zaoszczędzonym rozmiarem
6. Sprzątanie lokalnego pliku tymczasowego przez blok `finally` (także w razie błędu)

Imagick jest używany priorytetowo, gdy jest dostępny (wyższa jakość i jedyny silnik AVIF przez libheif na wielu serwerach). W przeciwnym razie przejmuje GD: obsługuje WebP od dawna, a AVIF od PHP 8.1.

**Kompresja oryginalnego JPEG jest nieodwracalna.** Gdy opcja _Kompresuj oryginał_ jest zaznaczona, wersja skompresowana zastępuje oryginał na filesystemie. Jeśli potrzebujesz odzyskać surowe źródła do innych zastosowań (druk, retusz), wyłącz tę opcję: zyski z WebP i AVIF i tak zachowasz.

## Zadanie cykliczne: nadrobienie istniejących obrazów

Aktywacja pluginu w sklepie, który ma już tysiące obrazów w bazie, nie uruchamia optymalizacji wstecznej. To celowe: konwersja 50 000 obrazów do AVIF naraz zapchałaby Twój serwer. Zamiast tego zadanie cykliczne `df_image_optimizer.optimize_pending` wykonuje się domyślnie co 15 minut:

1. Zapytanie SQL z LEFT JOIN na `df_image_optimizer` w celu wskazania mediów jeszcze niezoptymalizowanych
2. Przetworzenie partii 50 obrazów (rozmiar partii konfigurowalny)
3. Zakończenie i zwolnienie workera na kolejne zadanie

W sklepie z 10 000 obrazów licz około 50 godzin na nadrobienie wszystkiego w tle. Aby przyspieszyć:

- Zwiększ rozmiar partii w konfiguracji (spróbuj 100 albo 200)
- Użyj przycisku **Uruchom partię** na pulpicie kilka razy pod rząd
- Uruchom zadanie w pętli ręcznie przez 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 udostępniane motywom

Zarejestrowane są dwa helpery Twig, których możesz użyć w dowolnym szablonie motywu albo pluginu.

### Filtr `|df_cdn`

Przepisuje adres URL na CDN, jeśli jest włączony, a w przeciwnym razie zwraca adres bez zmian. Przydatne przy zasobach, które dołączasz ręcznie.

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

### Funkcja `df_picture()`

Renderuje kompletny znacznik `` ze źródłami AVIF, WebP i oryginalnym fallbackiem oraz wszystkimi skonfigurowanymi atrybutami (lazy, async, width/height).

```
{{ df_picture(
    media,
    alt='Accessible description',
    classes='product-image card-img',
    sizes='(max-width: 768px) 100vw, 50vw'
) }}
```

Generuje:

```
<picture>
    <source type="image/avif"
            srcset="https://cdn.example.com/media/foo.jpg.avif"
            sizes="(max-width: 768px) 100vw, 50vw">
    <source type="image/webp"
            srcset="https://cdn.example.com/media/foo.jpg.webp"
            sizes="(max-width: 768px) 100vw, 50vw">
    <img src="https://cdn.example.com/media/foo.jpg"
         alt="Accessible description"
         class="product-image card-img"
         sizes="(max-width: 768px) 100vw, 50vw"
         loading="lazy"
         decoding="async"
         width="1200"
         height="800">
</picture>
```

## Endpointy API administracji

Dostępne są trzy endpointy REST, uwierzytelniane standardowym tokenem Bearer administracji.

| Metoda | Trasa | Opis |
| --- | --- | --- |
| GET | `/api/_action/df-image-optimizer/stats` | Przegląd plus aktywność z 30 dni plus możliwości serwera |
| POST | `/api/_action/df-image-optimizer/run-batch` | Uruchamia partię. Opcjonalny parametr POST `batchSize` (domyślnie 50, maks. 500) |
| GET | `/api/_action/df-image-optimizer/capabilities` | Wykrywanie serwera (Imagick / GD / WebP / AVIF) |

**Przykład curl:**

```
TOKEN=$(curl -s -X POST https://shop.example.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.example.com/api/_action/df-image-optimizer/run-batch
    -H "Authorization: Bearer $TOKEN"
    -H "Content-Type: application/json"
    -d '{"batchSize":200}'
```

## Tworzone tabele

### `df_image_optimizer`

Jeden wiersz na zoptymalizowane medium. Unikalny klucz na `media_id`: nowa optymalizacja tego samego medium nadpisuje wiersz.

```
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       Original weight in bytes
bytes_saved       BIGINT       Cumulated savings (compression + WebP/AVIF delta)
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`

Opcjonalny dziennik błędów. Tylko do odczytu na potrzeby debugowania, bez automatycznego czyszczenia.

## Rozwiązywanie problemów

### "Pulpit pokazuje AVIF: niedostępne"

Twój serwer nie ma wymaganego stosu AVIF. Opcje:

- **Jeśli tylko GD**: sprawdź `php -m | grep gd` i `php -i | grep AVIF`. Potrzebne jest PHP 8.1+ _oraz_ GD skompilowane z `--with-avif`. Na nowszych Debianach i Ubuntu jest to domyślne.
- **Jeśli Imagick dostępny**: sprawdź `php -r "print_r(Imagick::queryFormats('AVIF'));"`. Puste? Twój Imagick nie jest skompilowany z libheif: konieczna rekompilacja albo przejście na GD.
- **Akceptowalny fallback**: zostaw AVIF wyłączone i skup się na WebP. Sam zysk z WebP jest już ogromny wobec natywnego JPEG w Shopware.

### "Pliki .webp są generowane, ale storefront pokazuje JPEG"

Kompilator motywu nie uwzględnił override'u Twig. Rozwiązanie:

```
sudo -u www-data setsid php bin/console theme:compile
sudo -u www-data setsid php bin/console cache:clear
```

Następnie sprawdź w DevTools przeglądarki (Chrome albo Firefox): otwórz zakładkę Sieć, przeładuj stronę produktu i spójrz na typ MIME ładowanych obrazów. Powinieneś zobaczyć `image/avif` albo `image/webp` zamiast `image/jpeg`.

### "Przesyłanie mediów zrobiło się wolne"

Zwłaszcza konwersja AVIF mocno obciąża CPU: licz od 1 do 3 sekund na obraz. Jeśli to przeszkadza, wyłącz autooptymalizację przy przesyłaniu (karta Ogólne) i zostaw przetwarzanie w tle wyłącznie zadaniu cyklicznemu. Przesyłanie znów staje się natychmiastowe, a obrazy są optymalizowane najpóźniej w ciągu 15 minut.

### "Miniatury .webp nie są generowane"

Sprawdź, czy _Przetwarzaj miniatury_ jest zaznaczone na karcie Ogólne. Następnie wygeneruj miniatury ręcznie, aby ponownie przeszły przez pipeline:

```
sudo -u www-data setsid php bin/console media:generate-thumbnails
```

### "Jak usunąć wszystkie wygenerowane pliki WebP/AVIF?"

Plugin nie usuwa ich automatycznie, nawet przy odinstalowaniu (aby chronić Twoje kopie zapasowe). Aby wyczyścić je ręcznie:

```
cd /path/to/shopware
find public/media -name "*.webp" -delete
find public/media -name "*.avif" -delete
```

### "Adresy CDN nie są stosowane wszędzie"

Sprawdź skonfigurowany zakres. Jeśli widzisz adresy origin dla zasobów motywu (`/theme/.../style.css`), to normalne przy domyślnym zakresie _Tylko media_. Przejdź na _Wszystkie zasoby statyczne_, jeśli Twój CDN jest skonfigurowany do serwowania wszystkich zasobów.

Zwróć też uwagę, że przepisywane adresy dotyczą renderowania Twig po stronie serwera. Jeśli Twój frontend wywołuje Store-API i odtwarza adresy po stronie JS, przepisywanie trzeba zastosować osobno po stronie klienta.

## Odinstalowanie

```
sudo -u www-data setsid php bin/console plugin:uninstall DfImageOptimizer
sudo -u www-data setsid php bin/console plugin:remove DfImageOptimizer
```

Przy odinstalowaniu Shopware pyta, czy chcesz zachować dane użytkownika:

- **Zachowaj** (domyślnie): tabele `df_image_optimizer` i `df_image_optimizer_log` zostają w bazie. Ponowna instalacja pluginu podejmie historię.
- **Nie zachowuj**: obie tabele są usuwane (DROP TABLE).

W obu przypadkach pliki `.webp` i `.avif` na filesystemie pozostają: użyj powyższych komend `find`, aby je w razie potrzeby wyczyścić.

## Aby pójść dalej

- Obserwuj swój wynik Core Web Vitals w Google Search Console: LCP powinien spaść w ciągu 2 do 4 tygodni od aktywacji
- Przetestuj w PageSpeed Insights przed i po: typowy zysk od 20 do 40 punktów na mobile
- Włącz też HTTP/2 albo HTTP/3 po stronie serwera, aby zwielokrotnić korzyść z CDN
- Połącz to z pełnostronicowym cache Shopware, aby uzyskać statyczne czasy odpowiedzi
