DataFirefly Image Optimizer: documentação Shopware 6
Instalação, configuração WebP/AVIF, integração de CDN, API Twig e resolução de problemas da extensão Image Optimizer para Shopware 6.6 e 6.7.
O DataFirefly Image Optimizer transforma automaticamente cada imagem de média do Shopware em variantes WebP e AVIF, recomprime os JPEG e PNG de origem, e reescreve os URLs para o seu CDN, sem alterar o tema. Esta documentação cobre a instalação, a configuração completa, a API Twig exposta aos temas e a resolução de problemas.
Instalação
A extensão é entregue em ZIP. Dois métodos de instalação, funcionalmente equivalentes.
Pela administração do Shopware
- Definições → Sistema → Extensões → Carregar uma extensão
- Selecione
DfImageOptimizer-1.0.0.zip - Clique em Instalar e depois em Ativar
- Limpe a cache: Definições → Sistema → Cache e Índice → Limpar
Por CLI (recomendado)
cd /caminho/para/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 é obrigatório depois da instalação para que a sobreposição Twig do componente de miniatura fique ativa no storefront. Sem esse passo, as etiquetas <picture> não serão geradas, mesmo que o WebP e o AVIF sejam produzidos.Verificação após a instalação
Vá ao menu de administração Catálogos → Image Optimizer. O painel tem de aparecer com um cartão Compatibilidade do servidor a indicar em tempo real:
- Versão do PHP detetada (8.2 no mínimo)
- Presença do Imagick (recomendado)
- Presença do GD (obrigatório)
- Suporte efetivo a WebP: tem de estar ✓
- Suporte efetivo a AVIF: pode estar ✗ consoante o servidor, não é bloqueante
- Motor recomendado: Imagick ou GD
Arquitetura em duas palavras
Quando uma imagem é carregada, a extensão escuta o evento de entidade media.written, carrega a imagem para um ficheiro temporário local, e produz em paralelo:
- O original recomprimido (substitui o ficheiro de origem se Comprimir original estiver marcado)
- Um irmão WebP ao lado, com extensão acumulada:
foo.jpg→foo.jpg.webp - Um irmão AVIF ao lado:
foo.jpg→foo.jpg.avif
As miniaturas do Shopware geradas pelo ThumbnailService nativo são tratadas da mesma forma. Do lado do storefront, a sobreposição Twig de storefront/component/image/thumbnail.html.twig envolve a etiqueta <img> num <picture> com fontes AVIF, WebP e alternativa original: o navegador escolhe automaticamente o formato mais leve que suporta.
Configuração
Acesso: Definições → Sistema → Extensões → DfImageOptimizer → Configurar. Sete cartões agrupam as opções.
Cartão «Geral»
| Opção | Predefinição | Efeito |
|---|---|---|
| Otimização automática no carregamento | Ativa | Aciona o pipeline de imediato a cada carregamento. Desative se preferir fazer tudo em segundo plano através do cron. |
| Tratar as miniaturas | Ativa | Gera WebP/AVIF também para as miniaturas do Shopware (tipicamente 4 a 6 tamanhos por imagem de origem). |
Cartão «WebP»
| Opção | Predefinição | Recomendação |
|---|---|---|
| Ativar WebP | Ativo | A manter ativo salvo caso muito específico. O WebP é suportado por 96 % dos navegadores. |
| Qualidade WebP (1-100) | 82 | 75 a 85 para um bom compromisso. 90+ para fotografia de topo, 70 para catálogos volumosos. |
| Lossless para PNG | Desativado | Ative apenas se os seus PNG contiverem texto ou gráficos nítidos (logótipos, ícones). Caso contrário, o modo lossy dá melhores ganhos. |
Cartão «AVIF»
| Opção | Predefinição | Recomendação |
|---|---|---|
| Ativar AVIF | Desativado | Ative se o painel indicar que o seu servidor suporta AVIF. Ganho típico de 50 % face ao JPEG, mas codificação mais lenta que o WebP. |
| Qualidade AVIF (1-100) | 55 | 45 a 65 para uma excelente renderização. O AVIF tolera qualidades mais baixas do que o JPEG e o WebP graças ao seu codec moderno. |
| Largura máxima para AVIF (px) | 2400 | Salvaguarda de CPU. As imagens acima disso são saltadas para AVIF mas mantêm o seu WebP. Aumente se tiver um servidor potente e precisar de AVIF em imagens grandes. |
IMG_AVIF compilado, ou Imagick com libheif. O painel Compatibilidade do servidor indica-lhe exatamente o que está disponível. Se o AVIF não for suportado, a opção fica inoperante mesmo que marcada: sem erro, apenas sem geração de AVIF.Cartão «Compressão»
| Opção | Predefinição | Recomendação |
|---|---|---|
| Comprimir os JPG/PNG originais | Ativo | Substitui o original pela sua versão recomprimida. Ação irreversível: desative se quiser conservar as fontes em bruto para futuras edições. |
| Qualidade JPEG (1-100) | 85 | 85 é a norma da fotografia web. Descer a 80 dá ganho adicional se a qualidade continuar visualmente aceitável. |
| Nível de compressão PNG (0-9) | 7 | 9 = compressão máxima mas 3 a 4× mais lenta. 7 é o equilíbrio normal. |
| Eliminar os metadados EXIF/ICC | Ativo | Ganho típico de 5 a 30 KB por fotografia vinda de câmara. Conserve se gerir conteúdo que exija perfis de cor precisos. |
Cartão «CDN»
| Opção | Predefinição | Explicação |
|---|---|---|
| Ativar a reescrita para CDN | Desativada | Se estiver desativada, os URLs apontam para a sua origem. Ative depois de configurar o seu CDN. |
| URL de base do CDN | — | Formato: https://cdn.exemplo.com sem barra final. Ex.: https://shop-cdn.b-cdn.net para BunnyCDN. |
| Âmbito da reescrita | Apenas médias | Ver detalhe abaixo. |
| Conservar as query strings | Ativo | Preserva os parâmetros de cache-busting (?v=1234) na reescrita. |
Detalhe dos três âmbitos:
- Apenas médias: reescreve apenas os URLs que começam por
/media/. É o mais seguro e cobre 95 % dos casos de uso típicos. - Médias e miniaturas: acrescenta
/thumbnail/. Útil se o seu storefront servir muitas miniaturas geradas dinamicamente. - Todos os recursos estáticos: acrescenta
/theme/,/bundles/e/assets/. Só escolha esta opção se o seu CDN estiver corretamente configurado para pull-cache de todos os recursos e se tiver testado em staging.
Cartão «Renderização no frontend»
| Opção | Predefinição | Efeito |
|---|---|---|
Saída em etiqueta <picture> |
Ativa | Envolve as <img> do storefront num <picture> com fontes AVIF/WebP. |
Acrescentar loading="lazy" |
Ativo | Lazy-loading nativo do navegador. A manter, salvo se tiver a sua própria solução. |
Acrescentar decoding="async" |
Ativo | Permite ao navegador descodificar em paralelo com o parsing do HTML. |
Forçar width/height |
Ativo | Anti-CLS (Cumulative Layout Shift). O navegador reserva o espaço do visual antes do carregamento. |
Cartão «Processamento em lote»
| Opção | Predefinição | Recomendação |
|---|---|---|
| Tamanho do lote da tarefa cron | 50 | 50 é um bom equilíbrio. Suba para 100 a 200 se precisar de recuperar um catálogo grande depressa e o seu servidor aguentar. |
| Intervalo do cron (minutos) | 15 | Informação apenas: o intervalo real é definido pela classe OptimizeImagesTask::getDefaultInterval(). Para o alterar de facto, mude o valor na tabela scheduled_task ou reinstale a extensão depois da alteração. |
Configurar um CDN: exemplos concretos
BunnyCDN (recomendado)
- Crie uma Pull Zone em bunny.net com o seu URL de origem, por exemplo
https://loja.exemplo.com - O BunnyCDN dá-lhe um hostname do tipo
shop-cdn.b-cdn.net - Na configuração da extensão, coloque:
https://shop-cdn.b-cdn.net - Escolha o âmbito Apenas médias para começar
- Ative a reescrita para CDN
A extensão injeta automaticamente <link rel="dns-prefetch" href="https://shop-cdn.b-cdn.net"> e <link rel="preconnect" href="https://shop-cdn.b-cdn.net" crossorigin> no <head> do storefront: ganho de 50 a 200 ms no primeiro pedido ao CDN.
Cloudflare
A Cloudflare em modo proxy DNS normal não exige reescrita de CDN: coloca automaticamente em cache no seu hostname principal. Mas se usar um Custom Hostname Cloudflare dedicado aos recursos (por exemplo cdn.exemplo.com), configure-o aqui. Ative também o Cache Reserve ou o Polish do lado da Cloudflare para beneficiar da otimização da Cloudflare por cima da sua.
KeyCDN
Configuração idêntica à do BunnyCDN: crie uma Pull Zone, obtenha o URL do tipo shop-12345.kxcdn.com, e configure-o na extensão com o prefixo https://.
AWS CloudFront
Crie uma distribuição CloudFront com o seu servidor Shopware como origem. O URL de distribuição é do tipo https://d1234abc.cloudfront.net, ou o seu domínio personalizado se tiver configurado um alias. Configure o TTL mínimo para 1 dia para aproveitar plenamente a cache.
Pipeline de otimização em detalhe
Para cada imagem (original ou miniatura) a tratar, a extensão executa os seguintes passos por ordem:
- Transferência da imagem de origem do filesystem público do Shopware para um ficheiro temporário local (
/tmp/dfimgopt_xxx.jpg) - Se Comprimir original estiver ativo: recompressão in-place com a qualidade configurada, eliminação dos metadados se estiver ativa. Se a versão recomprimida for menor do que a original, substitui o ficheiro de origem no filesystem.
- Se o WebP estiver ativo: conversão para WebP, escrita do irmão
foo.jpg.webpno filesystem público - Se o AVIF estiver ativo e a largura for ≤ largura máxima: conversão para AVIF, escrita do irmão
foo.jpg.avif - Registo na tabela
df_image_optimizercom contadores e tamanho poupado - Limpeza do ficheiro temporário local através de um bloco
finally(mesmo em caso de erro)
O Imagick é usado em prioridade quando está disponível (qualidade superior e único motor AVIF através de libheif em muitos servidores). O GD assume caso contrário: suporta WebP há muito tempo e AVIF desde o PHP 8.1.
Tarefa agendada: recuperar as imagens existentes
Ativar a extensão numa loja que já tem milhares de imagens na base de dados não desencadeia a otimização retroativa. É intencional: converter 50 000 imagens em AVIF de uma vez saturaria o seu servidor. Em vez disso, a tarefa agendada df_image_optimizer.optimize_pending corre a cada 15 minutos por predefinição:
- Consulta SQL com LEFT JOIN em
df_image_optimizerpara identificar os médias ainda não otimizados - Trata um lote de 50 imagens (tamanho de lote configurável)
- Termina e liberta o worker para a tarefa seguinte
Numa loja de 10 000 imagens, conte cerca de 50 horas para recuperar tudo em segundo plano. Para acelerar:
- Aumente o tamanho do lote na configuração (experimente 100 ou 200)
- Use o botão Lançar um lote do painel várias vezes seguidas
- Execute a tarefa em ciclo manualmente por 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 exposta aos temas
Estão registados dois helpers Twig, utilizáveis em qualquer template de tema ou de extensão.
Filtro |df_cdn
Reescreve um URL para o CDN se estiver ativo, e devolve o URL inalterado caso contrário. Útil para os recursos que inclui manualmente.
<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>
Função df_picture()
Renderiza uma etiqueta <picture> completa com fontes AVIF, WebP e alternativa original, mais todos os atributos configurados (lazy, async, width/height).
{{ df_picture(
media,
alt='Descrição acessível',
classes='product-image card-img',
sizes='(max-width: 768px) 100vw, 50vw'
) }}
Gera:
<picture>
<source type="image/avif"
srcset="https://cdn.exemplo.com/media/foo.jpg.avif"
sizes="(max-width: 768px) 100vw, 50vw">
<source type="image/webp"
srcset="https://cdn.exemplo.com/media/foo.jpg.webp"
sizes="(max-width: 768px) 100vw, 50vw">
<img src="https://cdn.exemplo.com/media/foo.jpg"
alt="Descrição acessível"
class="product-image card-img"
sizes="(max-width: 768px) 100vw, 50vw"
loading="lazy"
decoding="async"
width="1200"
height="800">
</picture>
Endpoints da API de administração
Estão disponíveis três endpoints REST, autenticados com o Bearer token normal da administração.
| Método | Rota | Descrição |
|---|---|---|
| GET | /api/_action/df-image-optimizer/stats |
Visão geral, atividade de 30 dias e capacidades do servidor |
| POST | /api/_action/df-image-optimizer/run-batch |
Lança um lote. Parâmetro POST opcional batchSize (predefinição 50, máximo 500) |
| GET | /api/_action/df-image-optimizer/capabilities |
Deteção do servidor (Imagick / GD / WebP / AVIF) |
Exemplo com curl:
TOKEN=$(curl -s -X POST https://loja.exemplo.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://loja.exemplo.com/api/_action/df-image-optimizer/run-batch
-H "Authorization: Bearer $TOKEN"
-H "Content-Type: application/json"
-d '{"batchSize":200}'
Tabelas criadas
df_image_optimizer
Uma linha por média otimizado. Chave única em media_id: uma nova otimização do mesmo média substitui a linha.
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 Peso original em bytes
bytes_saved BIGINT Acumulado de poupanças (compressão + 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
Registo opcional dos erros. Só de leitura, para depuração: sem limpeza automática.
Resolução de problemas
«O painel mostra AVIF: Indisponível»
O seu servidor não tem a stack AVIF necessária. Opções:
- Se só tiver GD: verifique
php -m | grep gdephp -i | grep AVIF. É preciso PHP 8.1+ e GD compilado com--with-avif. Em Debian/Ubuntu recentes, vem por predefinição. - Se o Imagick estiver disponível: verifique
php -r "print_r(Imagick::queryFormats('AVIF'));". Vazio? O seu Imagick não está compilado com libheif: é necessária recompilação ou passagem para GD. - Alternativa aceitável: deixe o AVIF desativado e concentre-se no WebP. O ganho só com WebP já é enorme face ao JPEG nativo do Shopware.
«As imagens .webp são bem geradas mas o storefront mostra JPEG»
O compilador de tema não teve em conta a sobreposição Twig. Solução:
sudo -u www-data setsid php bin/console theme:compile
sudo -u www-data setsid php bin/console cache:clear
Verifique depois com as DevTools do navegador (Chrome ou Firefox): abra o separador Rede, recarregue uma página de produto, e veja o tipo MIME das imagens carregadas. Deverá ver image/avif ou image/webp em vez de image/jpeg.
«O carregamento dos médias ficou lento»
A conversão AVIF em particular é intensiva em CPU: conte 1 a 3 segundos por imagem. Se for incómodo, desative a otimização automática no carregamento (cartão Geral) e deixe apenas a tarefa agendada tratar em segundo plano. Os carregamentos voltam a ser instantâneos e as imagens são otimizadas em 15 minutos no máximo.
«As miniaturas .webp não são geradas»
Verifique que Tratar as miniaturas está marcado no cartão Geral. Regenere depois manualmente as miniaturas para que voltem a passar pelo pipeline:
sudo -u www-data setsid php bin/console media:generate-thumbnails
«Como eliminar todos os ficheiros WebP/AVIF gerados?»
A extensão não os elimina automaticamente, nem sequer na desinstalação (para preservar as suas cópias de segurança). Para os limpar manualmente:
cd /caminho/para/shopware
find public/media -name "*.webp" -delete
find public/media -name "*.avif" -delete
«Os URLs do CDN não são aplicados em todo o lado»
Verifique o âmbito configurado. Se vir URLs de origem para recursos de tema (/theme/.../style.css), é normal com o âmbito predefinido Apenas médias. Passe para Todos os recursos estáticos se o seu CDN estiver configurado para servir todos os recursos.
Note também que os URLs reescritos dizem respeito à renderização Twig no servidor. Se o seu frontend chamar a Store API e reconstruir os URLs do lado do JS, terá de aplicar a reescrita do lado do cliente em separado.
Desinstalação
sudo -u www-data setsid php bin/console plugin:uninstall DfImageOptimizer
sudo -u www-data setsid php bin/console plugin:remove DfImageOptimizer
Na desinstalação, o Shopware pergunta se quer conservar os dados do utilizador:
- Conservar (predefinição): as tabelas
df_image_optimizeredf_image_optimizer_logficam na base de dados. Reinstalar a extensão retoma o histórico. - Não conservar: as duas tabelas são eliminadas (DROP TABLE).
Nos dois casos, os ficheiros .webp e .avif no filesystem mantêm-se: use os comandos find acima para os limpar se for necessário.
Para ir mais longe
- Vigie a sua pontuação de Core Web Vitals na Google Search Console: o LCP deve descer nas 2 a 4 semanas seguintes à ativação
- Teste com o PageSpeed Insights antes e depois: ganho típico de 20 a 40 pontos em telemóvel
- Ative também HTTP/2 ou HTTP/3 do lado do servidor para multiplicar o benefício do CDN
- Combine com uma cache de página completa do Shopware para tempos de resposta estáticos