Files
Claude Code 1ee91142d9 feat(wordpress): nova skill mcp-webp-express + doc MCP webpx na skill webp-express
Skill mcp-webp-express: MCP dedicado (webpx) para WebP Express multi-site
via WP-CLI/SSH, mesmo padrao mcp-wpfc. webp-express/SKILL.md: nova seccao
14 documentando o MCP construido e testado ao vivo em emanuelalmeida.pt.
2026-08-19 05:31:08 +01:00

40 KiB

name, description
name description
webp-express Gestão do plugin WebP Express (conversão automática de imagens para WebP) via WP-CLI e ficheiro de config em servidores CWP. Cobre localizar o ficheiro de config com hash variável, modos de operação (CDN friendly, Varied image responses, No conversion, Tweaked), reconversão em massa via `wp webp-express convert`, flush de webps, conversores disponíveis (imagemagick/imagick/gd vs cwebp/vips/ffmpeg/graphicsmagick/wpc/ewww) e as respectivas opções próprias, estrutura JSON completa do ficheiro de configuração (qualidade/encoding/near-lossless/alpha-quality por tipo de imagem, cache-control, alter HTML, redirection rules, web service), regras `.htaccess`, a fronteira com o Cloudflare, e o MCP `webpx` construído para gestão programática multi-site (§14). Usar quando "webp express", "converter imagens webp", "webp nao funciona", "reconverter imagens", "flush webp", "conversor imagemagick gd", "operation mode webp", "cdn friendly webp", "webp quality", "near lossless", "alter html webp", "cache control webp", "web service webp express", "mcp webp express", "webpx".

/webp-express — Conversão de imagens para WebP via WP-CLI

Gestão programática do plugin WebP Express (webp-express) em sites WordPress da frota, via WP-CLI no servidor CWP (server.descomplicar.pt, SSH porta 9443).

Fonte: CONFIG-Plugins-Referencia.md §5 (WebP Express) + verificação ao vivo em emanuelalmeida.pt (versão 0.25.15) + leitura completa do código-fonte nesta sessão: lib/classes/CLI.php, lib/classes/CachePurge.php, lib/classes/BulkConvert.php, e todos os ficheiros .inc/.php de lib/options/options/ (general, conversion-options incl. converter-options/*.php por conversor, redirection-rules, serve-options, alter-html, web-service-options, operation-mode.inc) — 43 ficheiros no total. Config JSON completo lido ao vivo do disco (não só campos vistos na UI).


Contexto CWP — sempre obrigatório

PATH=/home/USER/public_html
sudo -u USER /usr/local/bin/wp <comando> --path=$PATH

Acesso via SSH: ssh -p 9443 root@server.descomplicar.pt (alias server já configurado localmente).


1. Onde vive a configuração — NÃO é wp_options normal

A config principal do WebP Express vive num ficheiro JSON com nome imprevisível (hash no nome, muda por instalação/reinstalação):

wp-content/webp-express/config/config.<hash>.json

Nunca assumir o hash. Duas formas de o descobrir, por ordem de preferência:

# 1. Forma rápida — o hash está guardado numa option (sem precisar de find)
wp option get webp-express-config-hash --path=$PATH

# 2. Confirmar/descobrir via find quando a option não existe ou for preciso
#    validar o caminho real no disco
find $PATH/wp-content/webp-express/config -iname 'config.*.json'

O ficheiro em si:

HASH=$(wp option get webp-express-config-hash --path=$PATH)
cat $PATH/wp-content/webp-express/config/config.$HASH.json | python3 -m json.tool

Estado operacional (wp_options, separado da config)

Ao contrário da config, o estado vive mesmo em wp_options normais, todas com o prefixo webp-express-:

wp option get webp-express-state --format=json --path=$PATH
wp option get webp-express-migration-version --path=$PATH
wp option get webp-express-config-migrated-cve-2025-11379 --path=$PATH
wp option get webp-express-alter-html-options --format=json --path=$PATH

webp-express-state traz o resumo mais útil de uma só vez: workingConverterIds, workingAndActiveConverterIds, configured, htaccess-rules-saved-at-some-point, active-htaccess-dirs.

⚠️ Gotcha: convert_webp_status e webp_offset_* NÃO são do WebP Express

Numa auditoria com wp option list --search='*webp*' aparecem também convert_webp_status e vários webp_offset_* (webp_offset_thumbnail, webp_offset_large, etc.). São opções órfãs de outro plugin (não presente na lista activa de plugins do site) — não pertencem ao WebP Express e não devem ser lidas/alteradas ao auditar este plugin. Confirmar sempre com wp plugin list --format=json | grep -i webp que só webp-express está activo antes de interpretar options com "webp" no nome.


2. Modos de operação (operation-mode)

Fonte: lib/options/options/operation-mode.inc. Quatro valores possíveis:

Valor Nome na UI Comportamento
varied-image-responses Varied image responses Redirecciona jpeg/png para webp via .htaccess, mas só quando o browser envia Accept: image/webp. A mesma URL responde de forma diferente consoante o cliente — problemático para CDNs que não fazem Vary no header Accept
cdn-friendly CDN friendly jpeg é sempre servido como jpeg; em vez de variar a resposta, o WebP Express reescreve o HTML (<picture>/<img srcset>) para apontar directamente ao ficheiro .webp estático. Melhor HIT ratio em CDN, sem exigir forward do header Accept
no-conversion No conversion Não converte nada — usado quando outro plugin já faz a conversão e só se quer aproveitar a reescrita de HTML/redirecção do WebP Express
tweaked Tweaked Sem preset — todas as opções ficam editáveis individualmente (mostra secções redirection-rules e serve-options completas, que ficam escondidas nos outros modos); ao voltar a um preset perdem-se as afinações

Verificado em emanuelalmeida.pt: operation-mode: "cdn-friendly" — escolha correcta dado o site estar atrás do Cloudflare (evita depender de o Cloudflare fazer Vary: Accept correctamente, que nem sempre acontece nos planos gratuitos).

HASH=$(wp option get webp-express-config-hash --path=$PATH)
wp eval "echo json_decode(file_get_contents('wp-content/webp-express/config/config.$HASH.json'))->{'operation-mode'};" --path=$PATH

Para mudar de modo é preciso editar o ficheiro JSON directamente (não há comando wp option patch — não é uma option serializada) e depois correr wp webp-express convert --reconvert para regenerar tudo com as novas definições. Mutação em produção — nunca fazer sem autorização.

Nota de UI condicional por modo (relevante ao ler o código de lib/options/options/general/general.inc): as secções scope.inc, destination-folder.inc e destination-structure.inc só aparecem quando operation-mode != 'no-conversion'; cache-control.inc só aparece em tweaked, varied-image-responses ou cdn-friendly. O JSON de config mantém sempre todos os campos gravados, independentemente do que a UI mostra para o modo actual.


3. Reconverter imagens em massa — comando nativo wp webp-express

O plugin regista um comando WP-CLI próprio (lib/classes/CLI.php), não é preciso passar por wp eval. Fonte lida na íntegra nesta sessão — o plugin só regista dois subcomandos, não há mais:

wp help webp-express --path=$PATH
NAME
  wp webp-express
SUBCOMMANDS
  convert       Convert images to webp
  flushwebp     Flush webps

wp webp-express convert

# Ver o que falta converter, sem converter (dry preview por pasta)
wp webp-express convert --path=$PATH

# Converter tudo o que ainda não está convertido (media library + tema)
wp webp-express convert uploads --path=$PATH
wp webp-express convert themes --path=$PATH

# Forçar RECONVERSÃO de tudo (substitui webps já existentes)
wp webp-express convert uploads --reconvert --path=$PATH

# Limitar a uma subpasta
wp webp-express convert uploads/2026 --path=$PATH

# Só PNG / só JPEG
wp webp-express convert uploads --only-png --path=$PATH
wp webp-express convert uploads --only-jpeg --path=$PATH

# Forçar um conversor específico (ignora o stack de fallback)
wp webp-express convert uploads --converter=gd --path=$PATH

# Sobrepor qualidade/encoding só nesta corrida (não altera a config gravada)
wp webp-express convert uploads --quality=75 --encoding=lossy --path=$PATH

# Sobrepor near-lossless e alpha-quality só nesta corrida
wp webp-express convert uploads --near-lossless=60 --path=$PATH
wp webp-express convert uploads --alpha-quality=80 --path=$PATH

<location> aceita uploads, themes, plugins, wp-content ou index como "raiz de imagem", opcionalmente seguido de /subpasta. Sem argumento, lista quantos ficheiros por converter há em cada grupo, sem converter nada.

Flags completas do convert (confirmadas em CLI.php, docblock ## OPTIONS):

Flag Efeito Aplica-se a max-quality E png-quality
[<location>] Restringe a uma raiz de imagem (uploads|themes|plugins|wp-content|index), opc. /subpasta —
--reconvert Reconverte mesmo o que já está convertido —
--only-png Só PNG (image-types = 2) —
--only-jpeg Só JPEG (image-types = 1) —
--quality=<n> Sobrepõe qualidade (0-100) Sim — aplica ao mesmo valor max-quality e png-quality
--near-lossless=<n> Sobrepõe near-lossless (0-100) Sim — aplica a png-near-lossless e jpeg-near-lossless
--alpha-quality=<n> Sobrepõe alpha-quality (0-100) Só alpha-quality (PNG com transparência)
--encoding=<auto|lossy|lossless> Sobrepõe encoding Sim — aplica a png-encoding e jpeg-encoding
--converter=<id> Força um conversor específico, ignora o stack. Valores válidos: cwebp | vips | ewww | imagemagick | imagick | gmagick | graphicsmagick | ffmpeg | gd | wpc —

Nenhuma destas flags altera a config gravada em disco — são só para essa corrida.

wp webp-express flushwebp — limpar webps gerados

# Apaga TODOS os .webp gerados (força reconversão no próximo acesso/convert)
wp webp-express flushwebp --path=$PATH

# Só os que vieram de PNG
wp webp-express flushwebp --only-png --path=$PATH

Internamente chama CachePurge::purge() (lib/classes/CachePurge.php), que apaga recursivamente .webp em três locais: o cache dir (Paths::getCacheDirAbs()), o upload dir (só se destination-folder == 'mingled') e o dir de "bigger than source dummy files". Nunca apaga o original de um attachment registado na media library (MediaLibraryHelper::isRegisteredAttachmentOrThumbnail) — protecção interna contra apagar acidentalmente ficheiros errados quando modo mingled mistura originais e webps na mesma pasta.

Útil depois de mudar quality/encoding/conversor na config, antes de correr convert de novo — garante que não ficam webps antigos com as definições anteriores misturados com os novos.

Alternativa via wp-admin (sem SSH): Settings → WebP Express → aba "Bulk convert" tem os mesmos botões ("Bulk Convert" → popup de conversão em massa via AJAX; "Delete converted files" → popup que chama processAjaxPurgeCache(), o mesmo CachePurge::purge() do flushwebp). Há ainda um botão "Delete log files" na secção "Enable logging" (ver §7). O WP-CLI é preferível em produção por ser scriptável e não depender de timeout do browser em sites com muitas imagens. Nota: a conversão em massa via UI usa sempre as últimas definições gravadas (comentário no código-fonte de bulk-convert.inc: "the bulk conversion is using the last saved settings") — se acabaste de mudar qualidade/encoding no forms mas ainda não gravaste (Save), o bulk convert usa a versão antiga.


4. Conversores — stack de fallback e opções por conversor

webp-express tenta uma lista ordenada de conversores até um funcionar; cada entrada tem working: true/false gravado em webp-express-state (testado no arranque, não em cada conversão):

Conversor Estado em emanuelalmeida.pt Nota
imagemagick (binário CLI) ✅ working: true¹ Fallback preferido
imagick (extensão PHP) ✅ working: true¹
gd (extensão PHP, sempre disponível) ✅ working: true Último recurso, sempre presente em qualquer instalação PHP
cwebp (binário Google) ❌ working: false Não instalado no servidor CWP
vips ❌ working: false Não instalado
graphicsmagick/gmagick ❌ working: false Não instalado
ffmpeg ❌ working: false Não instalado
wpc (WebP Cloud / Remote WebP Express, API paga ou remota) ❌ working: false Não configurado (sem API key/URL)
ewww (requer plugin EWWW Image Optimizer) ❌ working: false Plugin não instalado neste site

¹ Nota lida directamente no JSON de config nesta sessão: no bloco converters[] do config actual, imagemagick e graphicsmagick aparecem com "working": false (o binário de sistema não responde), enquanto só gd tem "working": true. O webp-express-state (cache separada, recalculada a cada teste de auto-detecção) pode divergir ligeiramente do snapshot gravado no converters[] do JSON — confirmar sempre pelo webp-express-state para saber o estado corrente, o array converters do config json é sobretudo a lista de opções por conversor + ordem.

Sem impacto operacional — gd cobre 100% dos casos como último recurso; os conversores em falta são apenas alternativas mais rápidas/melhor compressão que não compensam instalar a nível de servidor só para este plugin. Verificar sempre workingConverterIds antes de forçar --converter=X num wp webp-express convert — se X não estiver na lista, o comando falha.

wp option get webp-express-state --format=json --path=$PATH | python3 -c "import json,sys; print(json.load(sys.stdin)['workingConverterIds'])"

Opções específicas por conversor (bloco converters[].options no JSON)

Fonte: lib/options/options/conversion-options/converter-options/*.php (um ficheiro por conversor) + o array converters do config JSON ao vivo.

Conversor Opções (options{}) Descrição
cwebp use-nice (bool), try-common-system-paths (bool), try-supplied-binary-for-os (bool), method (0-6), low-memory/"set-size"+size-in-percentage, command-line-options (string livre passada ao binário) method: trade-off velocidade/qualidade (0=rápido, 6=melhor). "Size" força tamanho-alvo em % do original em vez de qualidade (~2.5x mais lento). command-line-options aceita qualquer flag do cwebp real, ex. -low_memory -af -f 50 -sharpness 0 -mt
vips smart-subsample (bool), preset (none|default|photo|picture|drawing|icon|text) Preset ajusta várias opções internas consoante o tipo de conteúdo (não sobrepõe qualidade)
imagemagick use-nice (bool) Executa o binário convert; sem outras opções específicas
graphicsmagick (gmagick) use-nice (bool) Executa gm convert; sem outras opções específicas
ffmpeg use-nice (bool), method (0-6) Idêntico ao imagemagick mas via ffmpeg
gd skip-pngs (bool) Se true, PNGs passam para o próximo conversor da stack (Gd historicamente pior a comprimir PNG e teve bugs de transparência, hoje resolvidos)
imagick — (sem opções próprias) "imagick has no special options" no código
ewww api-key, api-key-2 (fallback) Serviço cloud pago (ewww.io); fee único, sem custo por conversão webp
wpc (Remote WebP Express / WPC) api-version (0|1), api-url, secret/api-key, crypt-api-key-in-transfer (bool) Delega a conversão a outra instalação WebP Express ou a um serviço webp-convert-cloud-service. Api 0 é legado (v0.1); usar 1 para instâncias WebP Express normais

use-nice: presente em quase todos os conversores baseados em binário — executa com prioridade reduzida (nice) para poupar recursos à custa de conversão ligeiramente mais lenta.

Use nice, try-common-system-paths, try-supplied-binary-for-os: o plugin traz binários cwebp pré-compilados para várias plataformas dentro do próprio plugin (try-supplied-binary-for-os) — útil quando o binário de sistema não existe mas o hosting permite exec().


5. Qualidade, encoding, near-lossless e metadata (conversion-options)

Fonte: lib/options/options/conversion-options/{quality,jpeg,png,metadata}.inc

  • valores ao vivo do JSON de emanuelalmeida.pt.

5.1. JPEG → WebP

Campo JSON Valor ao vivo Descrição
jpeg-encoding "auto" lossy (sempre lossy) ou auto (o plugin experimenta lossy e lossless e fica com o mais pequeno). Gd/Ewww não suportam auto
quality-auto true Se true, tenta detectar a qualidade original do jpeg e usar a mesma no webp (requer imagick/imagemagick/gmagick capazes de detectar qualidade); se false, usa quality-specific fixo
max-quality 80 Tecto para quality-auto: mesmo que o jpeg original tenha qualidade mais alta, nunca ultrapassa este valor. Recomendado 50-85
quality-specific 70 Qualidade fixa usada quando quality-auto=false OU como fallback quando a detecção de qualidade falhar
jpeg-enable-near-lossless true Aplica-se quando o encoding resultante é lossless: liga o pré-processamento "near-lossless" em vez de 100% lossless puro. Só suportado por cwebp e vips
jpeg-near-lossless 60 Nível 0 (máximo pré-processamento) a 100 (sem pré-processamento, = lossless puro)

5.2. PNG → WebP

Campo JSON Valor ao vivo Descrição
png-encoding "auto" lossless (default para PNG) ou auto (experimenta lossy e lossless, fica com o mais pequeno — não existe opção "sempre lossy" isolada para PNG na UI)
png-quality 85 Qualidade quando o resultado é lossy (via auto). Recomendado 60-90, tipicamente mais alto que jpeg pois PNG é usado para ícones/gráficos
alpha-quality 80 Qualidade específica do canal alfa (transparência), só relevante em encoding lossy com transparência. Gd/Ewww ignoram esta opção e mantêm o canal alfa sempre lossless
png-enable-near-lossless true Idêntico ao jpeg-enable-near-lossless, mas para PNG
png-near-lossless 60 Idêntico ao jpeg-near-lossless

5.3. Metadata

Campo JSON Valor ao vivo Descrição
metadata "none" none (não copia EXIF/etc. para o webp — mais pequeno) ou all (copia toda a metadata). Gd não suporta cópia de metadata — ignora esta opção sempre que Gd é o conversor efectivo

5.4. Outras opções gerais de conversão

Campo JSON Valor ao vivo Descrição
convert-on-upload true Converte a imagem (incl. todos os thumbnails gerados) no momento do upload para a media library. Hooka em handle_upload e image_make_intermediate_size. Pode abrandar o upload em temas com muitos tamanhos de thumbnail
image-types 3 Bitmask: 1=jpeg, 2=png, 3=ambos, 0=desactivado. Controla que tipos são convertidos/processados
prevent-using-webps-larger-than-original true Webps maiores que o original ficam sempre em disco mas não são usados (nem em .htaccess nem em Alter HTML) se esta opção estiver activa. Desde 0.25.5: em Alter HTML com picture + srcset, só omite o <source webp> se todos os webps do srcset forem maiores — considerar desactivar se muitas imagens têm srcset
enable-logging false Grava resultado de cada conversão em wp-content/webp-express/log/conversions/. Tem botão dedicado "Delete log files" na UI (popup purgelogpopup)

6. Estrutura completa do ficheiro de configuração (JSON)

Volcado ao vivo de emanuelalmeida.pt (wp-content/webp-express/config/config.<hash>.json) — esta é a lista completa de todas as chaves de topo que o plugin grava, incluindo as que não aparecem directamente numa única aba da UI:

{
  // --- Modo e âmbito ---
  "operation-mode": "cdn-friendly",              // varied-image-responses | cdn-friendly | no-conversion | tweaked
  "scope": ["uploads", "themes"],                 // subset de: uploads, themes, plugins, wp-content, index
  "image-types": 3,                                // bitmask: 1=jpeg 2=png 3=ambos 0=nenhum

  // --- Destino dos ficheiros webp ---
  "destination-folder": "separate",                // separate | mingled
  "destination-extension": "append",               // append (image.jpg.webp) | set (image.webp)
  "destination-structure": "image-roots",          // doc-root | image-roots

  // --- Cache-Control header ---
  "cache-control": "no-header",                    // no-header | set | custom
  "cache-control-custom": "public, max-age=31536000, stale-while-revalidate=604800, stale-if-error=604800",
  "cache-control-max-age": "one-week",             // one-second|one-minute|one-hour|one-day|one-week|one-month|one-year
  "cache-control-public": false,                   // true=public, false=private (só usado quando cache-control=set)

  // --- Robustez ---
  "prevent-using-webps-larger-than-original": true,
  "enable-logging": false,

  // --- Redirection rules (.htaccess) ---
  "enable-redirection-to-converter": false,        // só editável em modo "tweaked"/"varied-image-responses"
  "only-redirect-to-converter-on-cache-miss": false,
  "only-redirect-to-converter-for-webp-enabled-browsers": true,
  "do-not-pass-source-in-query-string": true,
  "redirect-to-existing-in-htaccess": false,
  "forward-query-string": true,
  "enable-redirection-to-webp-realizer": true,     // "criar webp sob pedido" (chave em cdn-friendly)

  // --- Qualidade/encoding jpeg ---
  "jpeg-encoding": "auto",                         // lossy | auto
  "jpeg-enable-near-lossless": true,
  "jpeg-near-lossless": 60,
  "quality-auto": true,
  "max-quality": 80,
  "quality-specific": 70,

  // --- Qualidade/encoding png ---
  "png-encoding": "auto",                          // lossless | auto
  "png-enable-near-lossless": true,
  "png-near-lossless": 60,
  "png-quality": 85,
  "alpha-quality": 80,

  // --- Stack de conversores, ordem = prioridade ---
  "converters": [
    { "converter": "cwebp", "options": { "use-nice": true, "try-common-system-paths": true, "try-supplied-binary-for-os": true, "method": 6, "low-memory": true, "command-line-options": "" }, "working": false },
    { "converter": "vips", "options": { "smart-subsample": false, "preset": "none" }, "working": false },
    { "converter": "imagemagick", "options": { "use-nice": true }, "working": false },
    { "converter": "graphicsmagick", "options": { "use-nice": true }, "working": false },
    { "converter": "ffmpeg", "options": { "use-nice": true, "method": 4 }, "working": false },
    { "converter": "wpc", "working": false, "options": { "api-key": "" } },
    { "converter": "ewww", "working": false },
    { "converter": "imagick", "working": false },
    { "converter": "gmagick", "working": false },
    { "converter": "gd", "options": { "skip-pngs": false }, "working": true }
  ],

  // --- Metadata / upload automático ---
  "metadata": "none",                              // none | all
  "convert-on-upload": true,

  // --- Serve options (resposta ao browser) ---
  "fail": "original",                              // original | 404 | report
  "success-response": "original",                  // original | converted

  // --- Alter HTML ---
  "alter-html": {
    "enabled": true,
    "replacement": "picture",                      // picture | url
    "hooks": "ob",                                  // content-hooks | ob (output buffering completo da página)
    "only-for-webp-enabled-browsers": false,
    "only-for-webps-that-exists": false,
    "alter-html-add-picturefill-js": true,
    "hostname-aliases": []                          // hostnames extra (CDN) cujas URLs também devem ser reescritas
  },

  // --- Web service (partilhar conversão com outros sites) ---
  "web-service": {
    "enabled": false,
    "whitelist": []                                 // [{ip, label, api-key, crypt-in-transfer}, ...]
  },

  // --- Snapshot de ambiente à data do save (diagnóstico, não editável) ---
  "environment-when-config-was-saved": { "...": "..." },
  "base-htaccess-on-these-capability-tests": { "...": "..." },
  "document-root": "/home/USER/site",
  "paths-used-in-htaccess": { "wod-url-path": "wp-content/plugins/webp-express/wod/webp-on-demand.php" }
}

6.1. Cache-Control header — detalhe

Fonte: lib/options/options/general/cache-control.inc.

cache-control Comportamento
no-header Não define header — deixa o servidor/CDN decidir
set Usa cache-control-public (public/private) + cache-control-max-age (preset de duração) para montar o header automaticamente
custom Usa literalmente a string em cache-control-custom — única forma de definir stale-while-revalidate/stale-if-error, não expostos nos presets

O texto de ajuda do próprio plugin recomenda custom com stale-while-revalidate/stale-if-error para melhor resiliência em falhas momentâneas do servidor de origem.

6.2. Scope — mapeamento de valores

Fonte: lib/options/options/general/scope.inc. O array scope[] é qualquer subconjunto ordenado alfabeticamente de uploads, themes, plugins, wp-content, index; a UI mapeia combinações comuns para nomes amigáveis:

scope (array) Nome na UI
["uploads"] Uploads only
["themes"] Themes only
["themes", "uploads"] Uploads and themes
["plugins", "themes", "uploads", "wp-content"] All content
["index", "plugins", "themes", "uploads", "wp-content"] Everything (including wp-admin)
Qualquer outra combinação Mostrado como "Custom: …"

Verificado em emanuelalmeida.pt: ["uploads", "themes"] → "Uploads and themes" (plugins/wp-content fora de âmbito).

6.3. Destination folder / extension / structure

Opção Valores Efeito
destination-folder separate (pasta dedicada wp-content/webp-express/webp-images/) | mingled (webp ao lado do original, só dentro de uploads) mingled é recomendado ao combinar com plugins de cache de página que sabem servir por extensão (ex. Cache Enabler), ou com Shortpixel
destination-extension append (imagem.jpg.webp) | set (imagem.webp) set conflitua se existir logo.jpg E logo.png na mesma pasta (colidem no mesmo logo.webp)
destination-structure doc-root (espelha caminho a partir da doc root) | image-roots (espelha caminho a partir da raiz de imagem — uploads/themes/etc) Recomendado image-roots em hosts com doc root mal configurada; doc-root reduz regras de rewrite necessárias em Nginx

Verificado em emanuelalmeida.pt: destination-folder: "separate", destination-extension: "append", destination-structure: "image-roots".


7. Redirection rules (.htaccess) — detalhe por opção

Fonte: lib/options/options/redirection-rules/*.inc. Estas opções só são todas editáveis em modo tweaked; nos outros modos, o preset do modo decide-as automaticamente (mas o valor gravado no JSON reflecte sempre o que está realmente activo em .htaccess).

Campo JSON Descrição
redirect-to-existing-in-htaccess Redirect interno directo para o .webp já existente, sem passar por PHP — mais rápido. Regra fica acima da regra de conversão
enable-redirection-to-converter Redirige jpeg/png (não convertidos) para webp-on-demand.php, que converte, grava e serve. Regra fica abaixo da anterior (só actua se ainda não existir webp)
enable-redirection-to-webp-realizer "Criar webp files upon request": redirige pedidos por um .webp que ainda não existe para webp-realizer.php, que procura o jpg/png correspondente, converte e serve — permite referenciar webps no HTML antes de existirem fisicamente. É a opção chave em modo cdn-friendly
only-redirect-to-converter-for-webp-enabled-browsers Só actua a regra do enable-redirection-to-converter quando o Accept header contém image/webp
only-redirect-to-converter-on-cache-miss Condição extra equivalente à funcionalidade usada por enable-redirection-to-webp-realizer, mas aplicada ao enable-redirection-to-converter — desnecessária se redirect-to-existing-in-htaccess já estiver activo
do-not-pass-source-in-query-string Se true (default recomendado), passa o path da imagem por env var em vez de query string, para não disparar firewalls que bloqueiam certas query strings
forward-query-string Encaminha a query string original do pedido para o script de conversão

8. Serve options (resposta ao browser após conversão)

Fonte: lib/options/options/serve-options/*.inc — só visível na UI em modo tweaked.

Campo JSON Valores Descrição
fail original (serve o jpg/png original) | 404 | report (relatório de erro em texto simples) Recomendado original em produção
success-response original | converted converted envia header Vary: Accept (indica que a resposta depende do Accept). Usar original se combinado com plugins de cache de página que não sabem variar por Accept (ex. Cache Enabler sem suporte dual-cache)

Verificado em emanuelalmeida.pt: fail: "original", success-response: "original".


9. Alter HTML — detalhe completo

Fonte: lib/options/options/alter-html/*.inc.

Campo JSON (alter-html.*) Valores Descrição
enabled bool Recomendado activar mesmo com redirecção activa: melhora cache em CDN e mantém extensão correcta ao fazer download de imagem
replacement picture | url picture: substitui <img> por <picture> com <source type="image/webp"> — funciona bem com cache de página, mas pode quebrar CSS div > img (usar div img). url: substitui directamente os URLs de imagem (src, srcset, lazy-load attrs, inline styles) — mais abrangente mas não funciona com cache de página excepto Cache Enabler
hooks content-hooks | ob content-hooks: hooka em the_content, the_excerpt, post_thumbnail_html, get_avatar, woocommerce_product_get_image, acf_the_content, dynamic_sidebar_before/after — mais leve. ob: intercepta a página inteira via output buffering — necessário se o tema/plugin não usa os hooks standard. HTML > 600kb ignora a alteração por protecção de memória
only-for-webp-enabled-browsers bool Só relevante com replacement=url: só faz a substituição quando o browser suporta webp (evita servir só-webp a browsers antigos sem JS de fallback)
only-for-webps-that-exists bool Se false ("Reference webps that haven't been converted yet" activo), permite referenciar webps que ainda não existem — requer enable-redirection-to-webp-realizer activo para funcionar
alter-html-add-picturefill-js bool Só relevante com replacement=picture: injecta polyfill picturefill.js para browsers sem suporte nativo a <picture> (~94% suporte nativo actual)
hostname-aliases array de strings Hostnames adicionais (ex. CDN) cujas imagens também devem ser processadas — útil se outro plugin já reescreve URLs para um CDN antes do WebP Express actuar

Verificado em emanuelalmeida.pt: enabled: true, replacement: "picture", hooks: "ob", only-for-webp-enabled-browsers: false, only-for-webps-that-exists: false, alter-html-add-picturefill-js: true, hostname-aliases: [].


10. Web service — partilhar conversão entre sites

Fonte: lib/options/options/web-service-options/*.inc. Permite que este site actue como servidor de conversão remota para outros sites que usam o conversor wpc/"Remote WebP Express" (ver §4).

Campo JSON (web-service.*) Descrição
enabled Activa o endpoint (URL exposto: Paths::getWebServiceUrl())
whitelist[] Lista de sites autorizados a usar este endpoint, cada entrada com: label (referência própria), ip (aceita wildcard *, ex. 212.91.* ou * para qualquer IP), api-key (chave arbitrária escolhida pelo utilizador, não um segredo gerado), crypt-api-key-in-transfer (bool — cifra a api-key no transporte; alguns setups antigos não suportam)

Verificado em emanuelalmeida.pt: web-service.enabled: false, whitelist: [] — não usado como servidor remoto neste site.


11. Bulk convert e cache purge (via UI e via CLI)

Fonte: lib/options/options/conversion-options/bulk-convert.inc + lib/classes/BulkConvert.php + lib/classes/CachePurge.php.

  • UI → "Bulk Convert" dispara AJAX que usa BulkConvert::getList() + conversão sequencial das últimas definições gravadas. Equivalente CLI: wp webp-express convert <scope> [--reconvert].
  • UI → "Delete converted files" dispara AJAX CachePurge::processAjaxPurgeCache(). Equivalente CLI: wp webp-express flushwebp [--only-png].
  • UI → "Delete log files" (dentro da secção "Enable logging") apaga wp-content/webp-express/log/conversions/*; sem equivalente CLI dedicado — usar wp eval ou apagar directamente via find/rm se necessário (nunca sem autorização em produção).
  • O filtro de listagem interno (BulkConvert::defaultListOptions) usa sempre only-unconverted: true por default (não reconverte o que já existe) e max-depth: 100 — nunca varre mais de 100 níveis de subpastas.
  • CachePurge::purge() nunca apaga .webp que estejam registados como attachment/thumbnail na media library (protecção em modo mingled, onde originais e webps partilham pasta).

12. Regras .htaccess

webp-express-state.configured: true e htaccess-rules-saved-at-some-point: true confirmam que as regras já foram gravadas — normalmente na pasta de cache do próprio plugin (active-htaccess-dirs: ["cache"]), não na raiz do site. Isto é o que faz o browser/Cloudflare receberem directamente o ficheiro .webp estático em vez de passar por PHP a cada pedido (modo cdn-friendly).

Se configured: false ou o site deixar de servir webps depois de uma migração/restauro, o passo de correcção é voltar à página de definições do plugin (wp-admin) e gravar de novo (o botão "Save" regrava o .htaccess) — não há comando WP-CLI dedicado a isto; o mais próximo é wp webp-express flushwebp seguido de convert, que não recria as regras .htaccess por si só.


13. Interacção com Cloudflare — quem faz o quê

Achado desta sessão, importante para não duplicar trabalho: a conversão/optimização de imagem feita pelo Cloudflare "Polish" está off neste site (não editável no plano Free) — o WebP não vem do Cloudflare, vem inteiramente do WebP Express a correr no WordPress. O Cloudflare aqui é só cache/CDN de distribuição do ficheiro .webp já gerado, não faz qualquer transformação de imagem própria. Não há sobreposição de funcionalidade a resolver, mas também não há optimização de imagem "grátis" via Cloudflare a contar — se o WebP Express falhar a converter, o Cloudflare não compensa.

Modo cdn-friendly foi escolhido precisamente por causa disto: ao reescrever o HTML para apontar directamente ao .webp estático (em vez de depender do Accept header e do Cloudflare fazer Vary correctamente), garante HIT ratio alto no cache do Cloudflare independentemente do plano.


14. MCP webpx — gestão programática (construído 19-08-2026)

Existe um MCP dedicado (mcp-webp-express, registado como webpx em ~/.omp/agent/mcp.json) que expõe as operações deste documento como tools, multi-site (todos os 8 aliases do bundle Descomplicar, mesmo padrão do wpfc/mcp-element-pack): spawn("ssh", ...), valor em base64 sobre stdin, sem ledger/rollback (fora do âmbito — ver emcp-tools para mudanças que precisem disso).

Diferença chave vs os outros MCPs da frota: a config deste plugin vive num ficheiro com hash no nome (§1), não numa wp_option — o MCP resolve o hash via webp-express-config-hash em cada chamada (nunca hardcoded) e preserva owner:group:permissões do ficheiro ao escrever (a ligação SSH corre como root; sem isto o wp-admin do site deixaria de conseguir gravar as próprias definições). webp-express-state também exigiu tratamento especial: o plugin grava-a como STRING JSON, não como array — um --format=json ingénuo devolve JSON duas vezes codificado.

Tools (9)

  • webpx_list_sites — sites conhecidos.
  • webpx_get_status / webpx_get_state — plugin instalado/activo/versão + webp-express-state (workingConverterIds, configured, htaccess-rules- saved-at-some-point).
  • webpx_get_config / webpx_set_config — ficheiro config.<hash>.json completo (§6).
  • webpx_get_converters / webpx_set_converter_options — stack de conversores (§4), opções por conversor + reordenação.
  • webpx_convert — wp webp-express convert (§3).
  • webpx_flushwebp — wp webp-express flushwebp (§3).

Guarda-corpos

  • webpx_set_config recusa gravar as chaves de diagnóstico só-leitura de §6 (environment-when-config-was-saved, base-htaccess-on-these-capability-tests, document-root, paths-used-in-htaccess).
  • webpx_set_config devolve um aviso explícito quando a chave alterada só tem efeito via .htaccess (operation-mode, scope, image-types, destination-*, redirection rules) — regenerar essas regras continua a exigir abrir wp-admin → Save uma vez (§12), sem equivalente WP-CLI.

Testado ao vivo em emanuelalmeida.pt (19-08-2026): leitura completa da config, escrita+leitura de volta com enable-logging (revertido), escrita+leitura de volta de gd.skip-pngs via webpx_set_converter_options (revertido), bloqueio confirmado ao tentar gravar document-root, convert em modo preview (0 ficheiros por converter, config já estável). Owner:group do ficheiro de config confirmado ealmeida:ealmeida 644 antes e depois da escrita. webpx_flushwebp e convert com location/reconvert reais não foram exercidos contra produção (mesmo padrão de comando já validado via convert em dry-run — risco desnecessário para a validação).

Erros comuns

Sintoma Causa Solução
find/cat no ficheiro de config falha, "No such file" Hash do nome do ficheiro mudou (reinstalação/migração) Nunca hardcode o hash — ler sempre wp option get webp-express-config-hash primeiro
Confundir convert_webp_status/webp_offset_* com definições do WebP Express Options órfãs de outro plugin já removido, mesmo prefixo textual "webp" Confirmar wp plugin list antes de interpretar qualquer option com "webp" no nome
wp webp-express convert --converter=cwebp falha Conversor não está na lista workingConverterIds (binário não instalado no servidor) Verificar webp-express-state antes de forçar um conversor específico
Imagens não aparecem como WebP no browser depois de convert .htaccess não gravado (configured: false) ou modo varied-image-responses com CDN sem Vary: Accept Confirmar configured: true em webp-express-state; preferir cdn-friendly atrás de Cloudflare
Webps antigos com qualidade errada persistem depois de mudar quality/encoding na config convert normal só converte o que falta, não regenera o que já existe wp webp-express flushwebp seguido de wp webp-express convert (ou convert --reconvert directo)
Bulk convert via UI usa qualidade/encoding antigos apesar de ter mudado o form O bulk convert usa sempre as últimas definições gravadas (Save), não o estado não-gravado do formulário Gravar (Save) antes de disparar "Bulk Convert"
Metadata (EXIF) desaparece do webp apesar de metadata: "all" Gd está a ser o conversor efectivo — Gd não suporta cópia de metadata, ignora sempre a opção Confirmar qual conversor está working/activo antes de assumir que metadata: "all" está a ser respeitado
Alpha quality/near-lossless parecem não ter efeito Conversor efectivo (Gd/Ewww) não suporta essas opções — são ignoradas silenciosamente Confirmar o conversor: near-lossless só em cwebp/vips; alpha-quality ignorado por Gd/Ewww
Selector CSS div > img deixa de funcionar depois de activar Alter HTML replacement: "picture" insere um elemento <picture> extra entre o div e o img Usar selector div img (descendente) em vez de div > img (filho directo), ou mudar para replacement: "url"

Fonte: CONFIG-Plugins-Referencia.md §5 + auditoria ao vivo original em emanuelalmeida.pt + expansão nesta sessão com leitura completa do código-fonte: lib/classes/CLI.php, CachePurge.php, BulkConvert.php, e os 43 ficheiros .inc/.php de lib/options/options/ (general, conversion-options + converter-options/*.php, redirection-rules, serve-options, alter-html, web-service-options, operation-mode.inc). Config JSON completo (config.<hash>.json) lido ao vivo do disco — todas as chaves de topo documentadas em §6 vêm directamente desse ficheiro, não só das que a UI mostra por modo.