- emcp-page-building, emcp-content-ops, emcp-site-audit: EMCP Tools MCP workflows verified live (atomic/legacy interplay, apply-template overwrite risk, create-theme-template goes live immediately, false-positive malware pattern in scan-security, change ledger + rollback) - elementor-pro-widgets: 30+5 native Elementor Pro widgets (curated catalog) - elementskit-widgets / powerpack-widgets: 42 + 97 third-party widgets, widgetType extracted from plugin source (not guessed by convention) - plugin.json bumped 1.2.0 -> 1.3.0, keywords + description updated - commits pending wordpress skills already present as untracked files (emcp-tools, wordfence, wp-activity-log, seguranca-descomplicar, webp-express, wp-fastest-cache, wp-font-perf, wp-meteor, wp-activity-log, redis-object-cache, app-for-cloudflare) and pending edits (rank-math, wp-cli, wp-content-seo-gate)
652 lines
44 KiB
Markdown
652 lines
44 KiB
Markdown
---
|
|
name: app-for-cloudflare
|
|
description: Gestão da zona Cloudflare a partir do wp-admin via App for Cloudflare® (`app-for-cf`, Digital Point) — SSL/TLS, Speed, Caching, Network, Scrape Shield, Bot Management, Super Bot Fight Mode, WAF real via Managed Ruleset, HSTS, Certificate Transparency, Leaked Credential Checks, Turnstile CAPTCHA, R2 media storage, Zero Trust Access, Page/Cache Rules, DMARC, Web Analytics, ferramentas de diagnóstico (request trace/IP/domain/WHOIS), purge de cache, guest page caching a nível de edge. Usar quando "app for cloudflare", "cloudflare wordpress", "zona cloudflare", "waf cloudflare", "bot management", "super bot fight mode", "hsts cloudflare", "rocket loader", "certificate transparency", "leaked credential checks", "bots de ia cloudflare", "ai_bots_protection", "is_robots_txt_managed", "managed ruleset", "purge cache cloudflare", "turnstile", "cloudflare r2", "cloudflare access", "page rules cloudflare", "cache rules cloudflare", "dmarc cloudflare", "cfPageCachingSeconds", "cfTurnstile", "app_for_cf", ou qualquer alteração a definições de zona Cloudflare/config do plugin num site do bundle Descomplicar.
|
|
---
|
|
|
|
# /app-for-cloudflare — Gestão de zona Cloudflare via App for Cloudflare®
|
|
|
|
Plugin `app-for-cf` (Digital Point), versão `1.10.0` (`APP_FOR_CLOUDFLARE_VERSION`),
|
|
instalado nos sites do bundle Descomplicar®.
|
|
Não é um simples proxy visual — a maior parte das definições de "boas
|
|
práticas" que o plugin lista **não vivem em `wp_options`**: são lidas e
|
|
escritas directamente na **Cloudflare API v4**, usando um token scoped
|
|
guardado numa única opção serializada. Confundir as duas camadas é o erro
|
|
mais comum ao operar este plugin.
|
|
|
|
**Fonte:** `CONFIG-Plugins-Referencia.md` §1 (App for Cloudflare®) e
|
|
`BUNDLE-Excelencia-WP.md` §2.2 e §2.4 (GEO/bots de IA) — mapeamento inicial
|
|
feito em `emanuelalmeida.pt` (16-08-2026), zona `574b243ebabd8ea2b8d89e68921f52cc`,
|
|
plano **Free Website**. Expandido na mesma sessão com leitura completa do
|
|
código-fonte (11.309 linhas em 61 ficheiros PHP,
|
|
`wp-content/plugins/app-for-cf/`): `Repository/Cloudflare.php` (2178
|
|
linhas — `getSettingsToManage()`, `setEasyMode()`, `updateSettings()`),
|
|
`Setup.php` (defaults de `wp_options`), `Admin/Template/Settings.php` (766
|
|
linhas — UI completa das 6 tabs), `Admin/Base/Admin.php` (estrutura das 14
|
|
páginas de menu), `Base/Pub.php` (657 linhas — guest page caching, purge,
|
|
preload), `Helper/Api.php` (gate Free/Pro), `Cron/Jobs.php` e
|
|
`Cli/PurgeCache.php` (automação de purge), e todos os 14 templates de
|
|
página em `Admin/Template/`.
|
|
|
|
---
|
|
|
|
## 0. As duas camadas de config — não confundir
|
|
|
|
| Camada | Onde vive | Como ler/escrever | Exemplos |
|
|
|---|---|---|---|
|
|
| **Config do plugin** (não é Cloudflare) | `wp_options.app_for_cf`, array PHP serializado, 18 chaves (ver §8) | `wp option get/patch` | `cfZoneId`, `cfAccountId`, `cloudflareAuth.token`, `cfPageCachingSeconds`, `cloudflarePreload`, `cfPurgeCacheOnAdminBar`, `cfTurnstile`, `cfProxy`, `cfR2Bucket` |
|
|
| **Config de zona Cloudflare** (as ~52 "boas práticas" + Bot Management + WAF, ver §1) | **Na Cloudflare, não no WordPress** | API v4 (`https://api.cloudflare.com/client/v4`), bearer token = `cloudflareAuth.token` da opção acima | `ssl`, `security_header` (HSTS), `waf`, `bot_management`, `rocket_loader`, `cache_level`, `hotlink_protection`, etc. |
|
|
|
|
Confirmado por leitura completa do código: **não existe** namespace WP REST
|
|
próprio exposto pelo plugin (`app-for-cf` não aparece em `rest_api_init` em
|
|
nenhum dos 61 ficheiros PHP) — todas as chamadas de configuração de zona
|
|
são directas à Cloudflare API v4 a partir do backend PHP do plugin
|
|
(`Api/Cloudflare.php`), usando o token guardado localmente. Para
|
|
automatizar fora do wp-admin, replicar essa mesma chamada directa
|
|
(`curl`/PHP) em vez de procurar um endpoint local que não existe.
|
|
|
|
A opção `cloudflareAuth` suporta **dois modos de autenticação** (ver
|
|
`Setup::defaults()`): `type: 'token'` (API token scoped, o único usado nos
|
|
sites do bundle) ou o modo legado `email` + `api_key` (Global API Key —
|
|
não usar, é o modo antigo e menos seguro da Cloudflare, mantido só por
|
|
compatibilidade retroativa no plugin).
|
|
|
|
### Ler a config do plugin (wp-cli)
|
|
|
|
```bash
|
|
PATH=/home/USER/public_html
|
|
|
|
# Opção completa (JSON)
|
|
wp option get app_for_cf --format=json --allow-root --path=$PATH
|
|
|
|
# Uma sub-chave
|
|
wp option pluck app_for_cf cfZoneId --allow-root --path=$PATH
|
|
wp option pluck app_for_cf cfPageCachingSeconds --allow-root --path=$PATH
|
|
|
|
# Editar uma sub-chave sem apagar as restantes (SEMPRE patch, nunca update, em opção serializada)
|
|
wp option patch update app_for_cf cfPageCachingSeconds 21600 --allow-root --path=$PATH
|
|
wp option patch update app_for_cf cloudflarePreload 1 --allow-root --path=$PATH
|
|
```
|
|
|
|
`cfProxy`, `cfR2Bucket`, `cloudflareAuth`, `cfTurnstile` são sub-arrays —
|
|
`wp option patch` só edita um nível; para sub-arrays aninhados usar
|
|
`wp eval` com `update_option()` sobre o array completo lido primeiro.
|
|
|
|
### Extrair o token para chamar a Cloudflare API directamente
|
|
|
|
```bash
|
|
TOKEN=$(wp eval 'echo maybe_unserialize(get_option("app_for_cf"))["cloudflareAuth"]["token"];' --allow-root --path=$PATH)
|
|
ZONE=$(wp eval 'echo maybe_unserialize(get_option("app_for_cf"))["cfZoneId"];' --allow-root --path=$PATH)
|
|
|
|
curl -s -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
|
|
"https://api.cloudflare.com/client/v4/zones/$ZONE/settings" | jq .
|
|
```
|
|
|
|
---
|
|
|
|
## 1. As definições de zona (por categoria) — lista completa do código
|
|
|
|
Fonte: `Repository/Cloudflare.php::getSettingsToManage()` (linhas 88-721),
|
|
a definição autoritativa usada pelo próprio plugin para desenhar a página
|
|
de Settings e para `updateSettings()`. **Achado desta expansão:** o número
|
|
"44" da auditoria original referia-se à contagem informal mostrada na UI
|
|
(que agrupa alguns campos); a contagem real de entradas no array
|
|
`getSettingsToManage()` é **52**. Lidas em bloco via `GET
|
|
/zones/{zone}/settings` (a maioria) + endpoints individuais para os campos
|
|
com `override_endpoint` (`security_header`, `certificate_transparency`,
|
|
`leaked_credential_checks`, `bot_management`, `speed_brain`, `fonts`,
|
|
`content_converter`, `origin_max_http_version`, `h2_prioritization`,
|
|
`settings/nel`, `flags` para `crawlhints`, `argo/tiered_caching`).
|
|
Escritas via `PATCH /zones/{zone}/settings/{setting_id}` com `{"value":
|
|
...}`, excepto onde a definição tem `overwrite_write_method` diferente
|
|
(`PUT` para tudo em `bot_management`, `POST` para
|
|
`leaked-credential-checks`/`ct/alerting`/`crawlhints`).
|
|
|
|
| Categoria | Definições |
|
|
|---|---|
|
|
| **Topo (fora de secção)** | `development_mode` (bool, bom = `off`), `security_level` (select: `off`/`essentially_off`/`low`/`medium`/`high`/`under_attack`, bom = `essentially_off`) — mostradas no topo da página Settings, não numa tab |
|
|
| **SSL/TLS** | `ssl` (modo de encriptação: `off`/`flexible`/`full`/`strict`/`origin_pull`), `always_use_https`, `security_header` (HSTS — ver §3), `min_tls_version` (`1.0`-`1.3`), `opportunistic_encryption`, `tls_1_3` (radio: `off`/`on`/`zrt` — zero round trip), `automatic_https_rewrites`, `ech` (Encrypted Client Hello), `certificate_transparency` (ver §4, `beta`), `tls_client_auth` |
|
|
| **Segurança** | `waf` (toggle legado, **deprecated** — ver §2), `bot_fight_mode` (Bot Fight Mode básico — ver §5a), `ai_bots_protection`, `crawler_protection` (ambos geridos via `bot_management` PUT — ver §5a), `bot_likely_automated`, `bot_definitely_automated`, `bot_verified_bots`, `bot_static_resource_protection`, `bot_optimize_wordpress`, `bot_enable_js` (Super Bot Fight Mode — ver §5a), `leaked_credential_checks` (ver §4), `challenge_ttl` (select 5min-12meses, bom = 30min), `browser_check`, `replace_insecure_js` |
|
|
| **Speed** | `polish` (select: `off`/`lossless`/`lossy`), `webp`, `speed_brain` (`beta`, substitui Rocket Loader/Mirage antigos), `fonts` (`beta`, Cloudflare Fonts — serve Google Fonts a partir do edge), `early_hints`, `rocket_loader` (deprecated para segurança — ver §2), `content_converter` (`beta`), `http2`, `origin_max_http_version` (int, bom = `2`), `http3`, `h2_prioritization`, `0rtt` (TLS 1.3 zero round trip) |
|
|
| **Caching** | `cache_level` (radio: `basic`/`simplified`/`aggressive`, bom = `aggressive`), `browser_cache_ttl` (select 0-12meses, `0` = respeitar headers de origem), `crawlhints` (`beta`, indica a crawlers quando o conteúdo mudou), `always_online`, `tiered_caching` (Argo Tiered Cache) |
|
|
| **Network** | `ipv6`, `websockets`, `pseudo_ipv4` (select: `off`/`add_header`/`overwrite_header`), `ip_geolocation`, `max_upload` (select 100-500MB), `nel` (Network Error Logging, `value.enabled` aninhado), `opportunistic_onion` |
|
|
| **Scrape Shield** | `email_obfuscation`, `hotlink_protection` |
|
|
|
|
```bash
|
|
# Ler uma definição individual
|
|
curl -s -H "Authorization: Bearer $TOKEN" \
|
|
"https://api.cloudflare.com/client/v4/zones/$ZONE/settings/rocket_loader" | jq .
|
|
|
|
# Escrever uma definição individual (formato standard "value")
|
|
curl -s -X PATCH -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
|
|
"https://api.cloudflare.com/client/v4/zones/$ZONE/settings/rocket_loader" \
|
|
-d '{"value":"off"}' | jq .
|
|
```
|
|
|
|
`webp`, `content_converter`, `speed_brain`, `fonts`, `crawlhints`,
|
|
`tiered_caching` e outros podem estar **plan-locked** (não editáveis no
|
|
plano Free Website) — a API devolve o valor actual mas ignora tentativas
|
|
de escrita; não é bug, é limite de plano. A UI do plugin marca isto
|
|
lendo `editable` do resultado da API (ver `override_result_editable_if_has`
|
|
no código) e desactiva o `<select>`/checkbox correspondente.
|
|
|
|
### EasyConfig — o que o botão "Easy config" aplica em bloco
|
|
|
|
`Repository\Cloudflare::setEasyMode()` (linha 723) aplica de uma vez, via
|
|
`POST /zones/{zone}/settings` (bulk) + 5 chamadas individuais:
|
|
|
|
```
|
|
0rtt=on, browser_cache_ttl=0, cache_level=aggressive, early_hints=on,
|
|
http3=on, ip_geolocation=on, ipv6=on, min_tls_version=1.2,
|
|
opportunistic_encryption=on, opportunistic_onion=on, pseudo_ipv4=off,
|
|
rocket_loader=off, tls_1_3=zrt, websockets=on,
|
|
security_level=essentially_off (fora do WordPress; 'medium' fora do XF)
|
|
|
|
+ settings/nel → {"value":{"enabled":false}}
|
|
+ settings/origin_max_http_version → {"value":"2"}
|
|
+ settings/speed_brain → {"value":"on"}
|
|
+ settings/fonts → {"value":"on"}
|
|
+ argo/tiered_caching → {"value":"on"}
|
|
```
|
|
|
|
Não toca em SSL/TLS (excepto `min_tls_version`/`opportunistic_encryption`),
|
|
Bot Management, WAF, HSTS nem Scrape Shield — o EasyConfig é só Speed +
|
|
Caching + Network básico. Preferir aplicar definição a definição (§7 desta
|
|
skill) para manter controlo e rasto de decisão, como já recomendado no
|
|
achado original.
|
|
|
|
---
|
|
|
|
## 2. WAF real — o toggle `waf` está morto, usar Managed Ruleset
|
|
|
|
O toggle legado `waf` está **deprecated para zonas novas**: `PATCH
|
|
/zones/{id}/settings/waf` devolve `1027 WAF is deprecated for this zone`
|
|
independentemente do valor enviado. O mecanismo real de protecção é a fase
|
|
de ruleset `http_request_firewall_managed`, que **pode estar completamente
|
|
vazia** (zero regras, zero protecção) mesmo num site "protegido pelo
|
|
Cloudflare" — foi o estado encontrado em `emanuelalmeida.pt` antes da
|
|
correcção.
|
|
|
|
```bash
|
|
# 1. Confirmar se a fase managed já tem entrypoint com regras
|
|
curl -s -H "Authorization: Bearer $TOKEN" \
|
|
"https://api.cloudflare.com/client/v4/zones/$ZONE/rulesets/phases/http_request_firewall_managed/entrypoint" | jq .
|
|
# Vazio/erro "could not find entrypoint" = zero protecção real, apesar do que o toggle `waf` sugere
|
|
|
|
# 2. Implantar o Cloudflare Managed Free Ruleset na fase managed
|
|
curl -s -X PUT -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
|
|
"https://api.cloudflare.com/client/v4/zones/$ZONE/rulesets/phases/http_request_firewall_managed/entrypoint" \
|
|
-d '{
|
|
"rules": [
|
|
{
|
|
"action": "execute",
|
|
"action_parameters": {
|
|
"id": "77454fe2d30c4220b5701f6fdfb893ba"
|
|
},
|
|
"expression": "true",
|
|
"description": "Cloudflare Managed Free Ruleset"
|
|
}
|
|
]
|
|
}' | jq .
|
|
```
|
|
|
|
`77454fe2d30c4220b5701f6fdfb893ba` é o ID do **Cloudflare Managed Free
|
|
Ruleset** — disponível em qualquer plano, incluindo Free Website. Testar
|
|
sempre com um pedido real (POST/AJAX contra o site) depois de implantar,
|
|
não confiar só no `200 OK` do PUT.
|
|
|
|
A fase `http_request_firewall_custom` (regras próprias, não geridas) fica
|
|
tipicamente vazia (`10003 could not find entrypoint`) num site sem regras
|
|
custom — não é erro, é "zero regras próprias, só o Managed Ruleset". O
|
|
plugin (versão Pro) gere regras custom através da página **Firewall**
|
|
(§10) — "User agents" e "IP addresses" são interfaces amigáveis para criar
|
|
regras Custom Rules na fase `http_request_firewall_custom` sem precisar de
|
|
escrever expressões Cloudflare manualmente.
|
|
|
|
**Rocket Loader não substitui isto.** `rocket_loader` é uma definição de
|
|
**Speed** (adia/reordena `<script>` no browser), não de segurança — o
|
|
próprio plugin marca-o `not_good_alert` (recomenda desligado). Testado
|
|
nesta sessão como hipótese de causa de CLS elevado num site: desligar não
|
|
resolveu o CLS, mas manter desligado continua a ser a recomendação do
|
|
plugin por outras razões (risco de quebra em sites com jQuery/Elementor).
|
|
`speed_brain` é o sucessor recomendado pela Cloudflare (substitui Rocket
|
|
Loader e Mirage), mas está marcado `beta` no código do plugin.
|
|
|
|
---
|
|
|
|
## 3. HSTS (`security_header`)
|
|
|
|
```bash
|
|
curl -s -X PATCH -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
|
|
"https://api.cloudflare.com/client/v4/zones/$ZONE/settings/security_header" \
|
|
-d '{
|
|
"value": {
|
|
"strict_transport_security": {
|
|
"enabled": true,
|
|
"max_age": 15552000,
|
|
"include_subdomains": true,
|
|
"preload": false,
|
|
"nosniff": true
|
|
}
|
|
}
|
|
}' | jq .
|
|
```
|
|
|
|
**Gotcha real desta sessão:** se a origem (nginx) já envia o seu próprio
|
|
header `Strict-Transport-Security`, **o HSTS do Cloudflare não o sobrepõe**
|
|
— é comportamento documentado, não bug. Confirmar com `curl -sI` que o
|
|
`cf-cache-status` do pedido é `MISS`/`DYNAMIC` (não é cache stale) e que o
|
|
`max-age` devolvido é o da origem, não o configurado no Cloudflare. Ajustar
|
|
o `max_age` a partir da origem (nginx) quando o objectivo for realmente
|
|
mudar o valor visto pelo browser.
|
|
|
|
`preload: false` é deliberado por omissão — entrar na lista de preload dos
|
|
browsers é quase irreversível (remoção demora meses/anos a propagar). Só
|
|
activar depois de HSTS estável em produção há semanas sem incidentes.
|
|
|
|
O "bom" (`good`) definido no código do plugin para este campo é
|
|
`max_age: 31536000` (12 meses), `include_subdomains: 1`, `preload: 1`,
|
|
`nosniff: ''` (vazio, i.e. não activa X-Content-Type-Options via este
|
|
mecanismo) — mais agressivo do que o valor sugerido na correcção original
|
|
desta skill (6 meses). Escolher em função do risco de subdomínios não
|
|
cobertos por HTTPS antes de ir para 12 meses + preload.
|
|
|
|
---
|
|
|
|
## 4. Certificate Transparency e Leaked Credential Checks
|
|
|
|
Endpoints próprios, fora do bulk `settings`:
|
|
|
|
```bash
|
|
# Certificate Transparency (alertas quando um certificado é emitido para o domínio)
|
|
curl -s -X POST -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
|
|
"https://api.cloudflare.com/client/v4/zones/$ZONE/ct/alerting" \
|
|
-d '{"enabled": true}' | jq .
|
|
|
|
# Leaked Credential Checks (avisa se credenciais usadas no site apareceram em leaks conhecidos)
|
|
curl -s -X POST -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
|
|
"https://api.cloudflare.com/client/v4/zones/$ZONE/leaked-credential-checks" \
|
|
-d '{"enabled": true}' | jq .
|
|
```
|
|
|
|
Ambos vinham `off` por omissão num site com anos de conta Cloudflare — não
|
|
assumir que "conta antiga = tudo activo por defeito"; a Cloudflare tem
|
|
adicionado features de segurança ao longo do tempo sem as retroactivar em
|
|
zonas já existentes.
|
|
|
|
---
|
|
|
|
## 5. Bot Management (endpoint `/bot_management`) — 7 campos + `is_robots_txt_managed`
|
|
|
|
Endpoint próprio: `GET`/`PUT /zones/{zone}/bot_management` (não faz parte
|
|
do bulk `settings`, e **não aceita `PATCH`**). Estes campos foram
|
|
verificados via chamada directa à API (não são geridos pela UI do plugin
|
|
através de `getSettingsToManage()`, ao contrário dos campos do §5a) — o
|
|
plugin não expõe `content_bots_protection`, `ai_training`, `ai_search`,
|
|
`ai_user` nem `is_robots_txt_managed` na sua própria página de Settings,
|
|
mas estes são campos reais e válidos do endpoint `bot_management` da
|
|
Cloudflare, geríveis por chamada directa à API.
|
|
|
|
| Campo | Padrão óptimo Descomplicar® | O que faz mal se ligado |
|
|
|---|---|---|
|
|
| `ai_bots_protection` | `disabled` | Bloqueia crawlers de IA (GPTBot, ClaudeBot, etc.) — visto `block` activo em 2 sites do bundle |
|
|
| `content_bots_protection` | `disabled` | Idem, granularidade diferente |
|
|
| `crawler_protection` | `disabled` | Bloqueia crawlers genéricos |
|
|
| `ai_training` | `disabled` | Bloqueia bots de treino de modelos |
|
|
| `ai_search` | `disabled` | Bloqueia bots de motores de busca IA |
|
|
| `ai_user` | `disabled` | Bloqueia bots accionados por utilizador de IA (ex. ChatGPT a navegar em nome do utilizador) |
|
|
| `fight_mode` | `false` | Desafia (challenge JS) tráfego automatizado por heurística — apanha crawlers legítimos de IA que não resolvem JS challenges, visto a devolver "Just a moment..." em vez de conteúdo real |
|
|
|
|
**Achado real desta sessão (GEO):** com `is_robots_txt_managed: true`, o
|
|
Cloudflare **injecta directivas `Disallow: /`** no `robots.txt` servido
|
|
para estes user-agents, por cima do ficheiro físico do site — mesmo que o
|
|
ficheiro físico já permita esses bots explicitamente. Parsers que fundem
|
|
grupos do mesmo user-agent aplicam o `Disallow` na mesma, tornando a
|
|
permissão do ficheiro físico letra morta.
|
|
|
|
```bash
|
|
# Ler estado actual
|
|
curl -s -H "Authorization: Bearer $TOKEN" \
|
|
"https://api.cloudflare.com/client/v4/zones/$ZONE/bot_management" | jq .
|
|
|
|
# Corrigir — PUT, NUNCA PATCH (PATCH devolve sempre 10405 Method not allowed,
|
|
# independentemente das permissões do token)
|
|
curl -s -X PUT -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
|
|
"https://api.cloudflare.com/client/v4/zones/$ZONE/bot_management" \
|
|
-d '{
|
|
"ai_bots_protection": "disabled",
|
|
"content_bots_protection": "disabled",
|
|
"crawler_protection": "disabled",
|
|
"ai_training": "disabled",
|
|
"ai_search": "disabled",
|
|
"ai_user": "disabled",
|
|
"fight_mode": false,
|
|
"is_robots_txt_managed": false
|
|
}' | jq .
|
|
```
|
|
|
|
Depois de corrigir, **purgar cache** (Cloudflare + cache local WP, ex. WP
|
|
Fastest Cache) — `robots.txt` costuma ter `cache-control:
|
|
max-age=315360000`, a correcção não aparece sem purge. Confirmar ao vivo
|
|
com `curl -sI` que `cf-cache-status` não é `HIT` e o corpo já não tem
|
|
`Disallow: /` para os bots visados.
|
|
|
|
### 5a. Super Bot Fight Mode — campos geridos pela própria UI do plugin
|
|
|
|
Ao contrário do §5 (chamada directa, campos fora da UI), estes 8 campos
|
|
**são** geridos por `getSettingsToManage()` e aparecem na tab "Security"
|
|
da página Settings do plugin. Todos escrevem no mesmo endpoint `PUT
|
|
/bot_management`, mas com nomes de campo JSON diferentes do que o `id` da
|
|
definição no plugin:
|
|
|
|
| ID no plugin | Campo real na API `bot_management` | Bom (`good`) |
|
|
|---|---|---|
|
|
| `bot_fight_mode` | `fight_mode` | `false` |
|
|
| `ai_bots_protection` | `ai_bots_protection` | `block` *(nota: o `good` do código é `block`, oposto do padrão Descomplicar do §5 — ver decisão abaixo)* |
|
|
| `crawler_protection` | `crawler_protection` | `enabled` *(idem — oposto do padrão Descomplicar)* |
|
|
| `bot_likely_automated` | `sbfm_likely_automated` (select `allow`/`block`/`managed_challenge`) | `allow` |
|
|
| `bot_definitely_automated` | `sbfm_definitely_automated` (select `allow`/`block`/`managed_challenge`) | `allow` |
|
|
| `bot_verified_bots` | `sbfm_verified_bots` (select `allow`/`block`) | `allow` |
|
|
| `bot_static_resource_protection` | `sbfm_static_resource_protection` (bool) | `false` |
|
|
| `bot_optimize_wordpress` | `optimize_wordpress` (bool) | `false` |
|
|
| `bot_enable_js` | `enable_js` (bool) — comentário no código: "a API diz que é editável, mas só é possível de facto em plano Pro ou superior" | `false` |
|
|
|
|
**Contradição intencional a documentar:** o `good` que o código do plugin
|
|
define para `ai_bots_protection`/`crawler_protection` é o valor "block"/
|
|
"enabled" (i.e. o próprio autor do plugin recomenda bloquear bots de IA
|
|
por omissão). A decisão Descomplicar® (documentada no §5 e no gotcha da
|
|
tabela §7) é o oposto — **nunca bloquear bots de IA em nenhum site do
|
|
bundle**, por ser GEO-crítico (visibilidade em AI Overviews/ChatGPT/
|
|
Perplexity). Ao corrigir zonas, ignorar deliberadamente o "good" do plugin
|
|
para estes 2 campos específicos e aplicar sempre `disabled`.
|
|
|
|
Todas as escritas neste grupo enviam `unset_on_write: ['using_latest_model']`
|
|
— o código remove explicitamente esse campo do payload antes de fazer
|
|
`PUT`, porque `using_latest_model` é campo só de leitura devolvido pela API
|
|
(indica se a Cloudflare está a usar o modelo de detecção de bots mais
|
|
recente) e a API rejeita o `PUT` se ele for reenviado.
|
|
|
|
---
|
|
|
|
## 6. Scopes de token — lista completa (21 permissões, do código de setup)
|
|
|
|
`Admin/Template/MultisiteSettings.php` e `Admin/Template/Settings.php`
|
|
embutem a lista completa e oficial de scopes recomendados pelo autor do
|
|
plugin (usada para construir o link de criação de token pré-preenchido no
|
|
dashboard Cloudflare) — muito mais granular do que os 6 grupos informais
|
|
documentados na versão anterior desta skill:
|
|
|
|
| Scope Cloudflare | Nível de acesso | Necessário para |
|
|
|---|---|---|
|
|
| `Account.Access: Apps and Policies` | Edit | Zero Trust Access (página Access, Pro) |
|
|
| `Account.Access: Organizations, Identity Providers, and Groups` | Read | Zero Trust Access — resolver grupos/IdPs nas políticas |
|
|
| `Account.Account Analytics` | Read | Dados agregados de conta (não usado nesta skill) |
|
|
| `Account.Account Settings` | Read + Edit | Detalhes/definições de conta Cloudflare |
|
|
| `Account.Allow Request Tracer` | Read | Página "HTTP request trace" (§10) |
|
|
| `Account.Billing` | Read | Info de plano/facturação Cloudflare mostrada no plugin |
|
|
| `Account.Intel` | Read | Páginas "IP address details"/"Domain details"/"WHOIS" (Cloudflare Intel API, §10) |
|
|
| `Account.Turnstile` | Edit | Criar/gerir sitekeys Turnstile CAPTCHA (§8, `cfTurnstile`) |
|
|
| `Account.Workers R2 Storage` | Edit | R2 media storage (página R2, Pro) |
|
|
| `Account.Workers Scripts` | Edit | Worker proxy (`cfWorkersSubdomain`/`cfProxy`, §8) |
|
|
| `User.API Tokens` | Read | O plugin lê as próprias permissões do token para colorir a checklist de setup a verde |
|
|
| `Zone.Analytics` | Read | Web Analytics / dashboards de tráfego |
|
|
| `Zone.Bot Management` | Edit | Bot Management + Super Bot Fight Mode (§5, §5a) — **separado** do Zone Settings, falta frequentemente no token gerado por omissão |
|
|
| `Zone.Cache Purge` | Purge | Purge de cache (página "Purge cache", botão admin bar) |
|
|
| `Zone.Cache Rules` | Edit | Cache Rules (página Rules, Pro) |
|
|
| `Zone.Firewall Services` | Edit | Firewall Rules, regras de User-Agent/IP (página Firewall, Pro) |
|
|
| `Zone.Page Rules` | Edit | Page Rules legadas (página Rules, Pro) |
|
|
| `Zone.SSL and Certificates` | Edit | Certificate Transparency, TLS client auth |
|
|
| `Zone.Zone` | Edit | Operações de gestão da própria zona |
|
|
| `Zone.Zone Settings` | Edit | As ~52 definições de zona do §1 (SSL/TLS, Speed, Caching, Network, Scrape Shield) |
|
|
| `Zone.Zone WAF` | Edit | WAF/Managed Ruleset (§2) |
|
|
|
|
`Zone.DNS` **não está na lista oficial do plugin** — o plugin não gere DNS
|
|
(DMARC/SPF/DKIM são lidos como registos públicos via `dig`, ver §7/§10, não
|
|
via API Cloudflare autenticada).
|
|
|
|
**Sintoma de scope em falta:** a API devolve `403` ou o próprio plugin
|
|
mostra um erro de permissão específico à operação, não um erro genérico de
|
|
autenticação — o token pode estar válido e ainda assim faltar-lhe
|
|
exactamente o scope daquela chamada. Testado nesta sessão: token com `Zone
|
|
SSL/Settings Edit` funcionava para as definições de zona mas falhava em
|
|
Bot Management até se alargar explicitamente o scope no dashboard
|
|
Cloudflare (`My Profile → API Tokens → editar token`).
|
|
|
|
---
|
|
|
|
## 7. Gotchas e erros comuns
|
|
|
|
| Sintoma | Causa | Solução |
|
|
|---|---|---|
|
|
| `PATCH /zones/{id}/settings/waf` → `1027 WAF is deprecated for this zone` | Toggle legado morto para zonas novas | Implantar Managed Ruleset na fase `http_request_firewall_managed` (§2) |
|
|
| `PATCH /zones/{id}/bot_management` → `10405 Method not allowed` | Endpoint só aceita `PUT` | Usar `PUT` sempre, mesmo para alterar um único campo (envia o objecto completo) |
|
|
| Correcção de `robots.txt`/HSTS não aparece no browser | Header/ficheiro servido a partir de cache (Cloudflare e/ou plugin de cache WP) | Purgar Cloudflare + cache WP local; confirmar `cf-cache-status` não é `HIT` antes de validar |
|
|
| HSTS configurado no Cloudflare mas browser continua a ver `max-age` diferente | Origem (nginx) já envia o seu próprio header `Strict-Transport-Security` — Cloudflare **não sobrepõe** HSTS que a origem já envia | Ajustar na origem, ou aceitar que o Cloudflare é só fallback para origens sem HSTS próprio |
|
|
| Regra de firewall/Transform Rule com operador `matches` (regex) falha ou não fica disponível na UI | `matches` exige plano **Business** (WAF Advanced) | Reescrever a expressão com `in`, `eq` ou `contains` — disponíveis em qualquer plano, incluindo Free |
|
|
| `wp option update app_for_cf '...'` apaga sub-chaves que não estavam no valor enviado | `wp option update` substitui a opção inteira; `app_for_cf` é um array serializado | Usar `wp option patch update app_for_cf <chave> <valor>` para editar uma sub-chave sem tocar nas restantes |
|
|
| R2 (media storage) devolve `10042 Please enable R2 through the Cloudflare Dashboard` | R2 não está activado a nível de **conta** (não é definição de zona nem do plugin) | Activar manualmente no dashboard Cloudflare da conta antes de qualquer chamada à API de R2 |
|
|
| `ai_bots_protection`/`crawler_protection` a `block`/`enabled` num site do bundle | Divergência do padrão óptimo — visto em `carstuff.pt` e `solarfvengenharia.com` nesta sessão; **o próprio `good` do código do plugin recomenda `block`** (§5a), por isso corrigir manualmente sempre que se aplicar EasyConfig ou se seguir uma recomendação genérica do plugin | Corrigir para `disabled` via `PUT /bot_management` (§5) — decisão explícita: nunca bloquear bots de IA em nenhum site Descomplicar |
|
|
| Página "Public page caching"/"Purge cache"/analytics parecem não fazer nada de imediato | `handleHeaders()` só define `Cache-Control: max-age=0,s-maxage=X` — depende do Cloudflare respeitar esse header (`cache_level`/`browser_cache_ttl` compatíveis) e de não haver cookies de sessão a bloquear o cache (ver §9) | Confirmar `browser_cache_ttl` = "Respect existing headers" (`0`) e `cache_level` ≠ `basic`; testar em aba anónima sem cookies `wp-*`/`wordpress_*`/`comment_*`/`woocommerce_*` |
|
|
| Botões "Firewall", "Access", "Rules" (criar regra), "R2", "Copy from...", "License key" aparecem desactivados/a cinzento ou com classe `pro` | Funcionalidade gated para a versão **Premium/Pro** do plugin (`Helper\Api::check()` — ver §11) | Confirmar licença activa (`cfLicenseKey`) ou aceitar a limitação no plano Free |
|
|
| `wp option get app_for_cf` mostra `cfTurnstile:["0"]` em vez do array completo com `siteKey`/`onLogin`/etc. | Turnstile nunca foi activado neste site — o checkbox "Use Turnstile CAPTCHA" desmarcado grava só `[0]` (o `<input type="hidden" value="0">` do formulário), não o array completo de `Setup::defaults()` | Normal em sites sem Turnstile configurado; a estrutura completa (13 sub-chaves, ver §8) só aparece depois de gerar uma sitekey e gravar o formulário |
|
|
|
|
---
|
|
|
|
## 8. Config do plugin (`wp_options.app_for_cf`) — as 18 chaves em detalhe
|
|
|
|
Fonte: `Setup::defaults()` (schema oficial de instalação) cruzado com a
|
|
leitura ao vivo (`wp option get app_for_cf`) em `emanuelalmeida.pt`
|
|
(16-08-2026) — as 18 chaves batem certo entre defaults e produção.
|
|
|
|
```json
|
|
{"cfWorkersSubdomain":"","cfProxy":{"image":"0","url":"0"},"cfR2Bucket":{"media":""},"cfAccountId":"a8b00ad3227d729a146143a6a85a7522","cfZoneId":"574b243ebabd8ea2b8d89e68921f52cc","cfTokenId":"6b6d24fe8d324112ea4cfc328bf16f6c","cfZone":"emanuelalmeida.pt","cfPageCachingSeconds":"21600","cloudflareAuth":{"token":"cfut_..."},"cloudflareFirewallExpireDays":"7","cloudflareBlockIpsSpamClean":"0","cfExternalDataUrl":"","cloudflarePreload":"1","cfImagesTransform":"0","cfLicenseKey":"","cfPurgeCacheOnAdminBar":"1","cfTurnstile":["0"],"LockSettingsUserId":"1"}
|
|
```
|
|
|
|
| Chave | Tipo/Default | O que faz |
|
|
|---|---|---|
|
|
| `cfWorkersSubdomain` | string, `''` | Subdomínio `*.workers.dev` da conta Cloudflare, usado quando o Worker proxy (R2/imagens) está activo |
|
|
| `cfProxy.image` / `cfProxy.url` | `0`/`1` cada | Toggle interno para saber se URLs de imagem/media já estão a ser reescritas para servir via Worker/R2 (usado por `filterWpGetAttachmentUrl()`/`filterWpCalculateImageSrcset()` em `Base/Pub.php`) |
|
|
| `cfR2Bucket.media` | string, `''` | Nome do bucket R2 escolhido/criado para armazenar media da biblioteca WordPress (feature Pro, página R2) |
|
|
| `cfAccountId` | string | ID da conta Cloudflare — resolvido automaticamente por `getZoneId()` a partir do hostname na primeira chamada, cacheado aqui |
|
|
| `cfZoneId` | string | ID da zona Cloudflare — idem, cacheado para evitar `listZones()` a cada pedido |
|
|
| `cfTokenId` | string | ID do token API (não o valor secreto) — mostrado na UI como referência ("Token ID: ...") para o admin confirmar qual token está activo |
|
|
| `cfZone` | string | Nome do domínio da zona (ex. `emanuelalmeida.pt`), cacheado junto com `cfAccountId`/`cfZoneId` |
|
|
| `cfPageCachingSeconds` | int (segundos), `''` (vazio = desligado) | Tempo de `s-maxage` aplicado ao HTML para guests (§9) — `0`/vazio desliga o guest page caching |
|
|
| `cloudflareAuth.type` | `'token'` ou `'email'` | Modo de autenticação — `token` é o único usado/recomendado; `email`+`api_key` é o modo legado Global API Key |
|
|
| `cloudflareAuth.token` | string secreta | Bearer token da Cloudflare API, scoped (ver permissões no §6) |
|
|
| `cloudflareAuth.email` / `cloudflareAuth.api_key` | string, `''` | Só usados se `type = 'email'` (não usar) |
|
|
| `cloudflareFirewallExpireDays` | int, default `7` (1-90) | Dias até uma regra de firewall **criada automaticamente pelo plugin** (ex. bloqueio de IP de spammer, feature Pro) expirar sozinha |
|
|
| `cloudflareBlockIpsSpamClean` | `0`/`1`, default `1` | Se `1`, bloqueia automaticamente (feature Pro) o IP de um utilizador cujo comentário foi marcado como spam pela fila de moderação do WordPress |
|
|
| `cfExternalDataUrl` | string URL, `''` | URL pública onde o media fica acessível quando R2 está activo — normalmente auto-preenchido ao activar R2, não editar manualmente salvo troubleshooting |
|
|
| `cloudflarePreload` | `0`/`1`, default `1` | Se `1`, o plugin usa hooks `script_loader_tag`/`style_loader_tag`/`wp_footer` para emitir headers HTTP `Link: <url>;rel=preload` (até 10 recursos) — funciona em conjunto com a definição de zona `early_hints` |
|
|
| `cfImagesTransform` | `0`/`1`, default `0` | Se `1`, activa **Cloudflare Images Transform** para blocos de imagem/media (serve AVIF/WebP a browsers modernos, formatos mais antigos a browsers antigos, qualidade reduzida em ligações muito lentas) — requer activação também a nível de zona no dashboard Cloudflare |
|
|
| `cfLicenseKey` | string, `''` | Chave de licença da versão Premium/Pro do plugin — sem isto, `Helper\Api::check()` devolve sempre `false` (ver §11) |
|
|
| `cfPurgeCacheOnAdminBar` | `0`/`1`, default `0` | Se `1`, mostra um botão de purge de cache com um clique na admin bar do WordPress |
|
|
| `cfTurnstile` | array com 13 sub-chaves quando activo: `siteKey`, `secretKey`, `onRegister`, `onLogin`, `onPassword`, `onComment`, `onContactForm7`, `onHtmlForms`, `onMetForm`, `onWPForms`, `onWooCommerceRegister`, `onWooCommerceLogin`, `onWooCommercePassword` | CAPTCHA Turnstile aplicado por contexto — cada `onX` é um toggle independente que decide se o widget Turnstile aparece nesse formulário específico (registo/login/reset password/comentários WP nativos, WooCommerce, e os plugins de formulário Contact Form 7/HTML Forms/MetForm/WPForms se estiverem instalados) |
|
|
| `LockSettingsUserId` | `0` ou ID de utilizador WP | Se preenchido com um ID de utilizador, **só essa conta WordPress** pode alterar as definições Cloudflare a partir do wp-admin — risco: apagar essa conta ou trocar de utilizador tranca o acesso às definições |
|
|
|
|
`network_exclude` (visto em código de multisite, `Settings.php` linha 290)
|
|
é uma chave adicional só relevante em instalações multisite — indica que
|
|
um site individual optou explicitamente por **não** herdar o token
|
|
API de rede.
|
|
|
|
---
|
|
|
|
## 9. Guest page caching (HTML a nível de edge) — como funciona de facto
|
|
|
|
Página "Public page caching" (§10) e a chave `cfPageCachingSeconds` (§8)
|
|
não usam Page Rules nem Cache Rules Cloudflare — usam um mecanismo mais
|
|
simples e mais portável: o hook `wp_headers` do WordPress
|
|
(`Base\Pub::handleHeaders()`, `Base/Pub.php` linha 276) define
|
|
```
|
|
Cache-Control: max-age=0,s-maxage=<cfPageCachingSeconds>
|
|
```
|
|
em toda resposta HTML elegível. `max-age=0` diz ao browser para não
|
|
cachear localmente; `s-maxage=<N>` diz a caches partilhadas (o edge da
|
|
Cloudflare) para cachear durante N segundos — desde que a definição de
|
|
zona `browser_cache_ttl` esteja em `0` ("Respect Existing Headers", o
|
|
padrão recomendado no §1) e `cache_level` não seja `basic`.
|
|
|
|
**Critérios de elegibilidade** (`pageCachingCriteria()`, filtráveis via
|
|
`app_for_cf_guest_page_cacheable`):
|
|
- Utilizador **não** tem sessão WordPress activa (`is_user_logged_in()`
|
|
falso)
|
|
- Nenhum cookie do browser começa por `wp-`, `wordpress_`, `comment_`
|
|
ou `woocommerce_` (senão a página é tratada como dinâmica/pessoal e o
|
|
header de cache não é aplicado)
|
|
- Pedido não é para `/wp-login.php`
|
|
- Content-Type da resposta começa por `text/html`
|
|
- Página não é 404
|
|
- `WP_DEBUG` não está activo
|
|
|
|
Por omissão o valor sugerido na UI é 6 horas (`21600` segundos, a mesma
|
|
opção `default` usada em `CachingGuestPage.php`); opções disponíveis vão
|
|
de 5 minutos a 24 horas, filtráveis via `app_for_cf_cache_times`, e o
|
|
limite máximo é derivado da vida do nonce do WordPress
|
|
(`DAY_IN_SECONDS - 3600`, tipicamente 23h).
|
|
|
|
```bash
|
|
# Ler/alterar o tempo de guest page caching
|
|
wp option pluck app_for_cf cfPageCachingSeconds --allow-root --path=$PATH
|
|
wp option patch update app_for_cf cfPageCachingSeconds 21600 --allow-root --path=$PATH # 6h
|
|
wp option patch update app_for_cf cfPageCachingSeconds '' --allow-root --path=$PATH # desligar
|
|
```
|
|
|
|
Como não é uma Page/Cache Rule, **não aparece no dashboard Cloudflare**
|
|
como regra — só é visível inspeccionando o header `Cache-Control` da
|
|
resposta HTTP (`curl -sI https://SITE/`) e o `cf-cache-status`.
|
|
|
|
---
|
|
|
|
## 10. As 14 páginas de admin — o que cada uma faz
|
|
|
|
Estrutura de menu confirmada em `Admin/Base/Admin.php`. O item de topo
|
|
(`Cloudflare`, ícone `dashicons-cloud`) mostra um badge `!` quando não há
|
|
token configurado.
|
|
|
|
| Slug (`page=`) | Título no menu | O que faz |
|
|
|---|---|---|
|
|
| `app-for-cf_caching` | **Public page caching** | Toggle + selector de tempo para o guest page caching do §9 (`cfPageCachingSeconds`) |
|
|
| `app-for-cf_firewall` | **Firewall** | 3 tabelas: **Firewall Rules** (link "Create rule" abre o dashboard Cloudflare — Pro), **User agents** (regras de bloqueio por user-agent geridas inline — Pro) e **IP addresses** (bloqueio manual por IP — Pro); todas suportam bulk enable/disable/delete via `bulkActionNotice()` |
|
|
| `app-for-cf_access` | **Access** | Lista de Zero Trust Access Apps + Groups da conta, com delete em massa (feature **Pro** — cria políticas de acesso, ex. proteger `/wp-admin` com SSO) |
|
|
| `app-for-cf_rules` | **Rules** | 2 tabelas: **Page Rules** legadas (link "Create page rule" abre dashboard — Pro) e **Cache Rules** modernas (link "Create cache rule" — Pro) |
|
|
| `app-for-cf_r2` | **R2 (media storage)** | Explica e liga a biblioteca de media do WordPress a um bucket Cloudflare R2 (10GB grátis, depois $0.015/GB); requer token válido **e** licença Pro |
|
|
| `app-for-cf_cache` | **Purge cache** | Botão único "Purge Cloudflare cache..." — chama `purgeCache()` sem filtro (`Purge Everything`) |
|
|
| `options-general.php?page=app-for-cf` | **Settings** (link para `wp-admin/options-general.php?page=app-for-cf`) | A página principal com as 6 tabs de definições de zona (Setup/SSL-TLS/Security/Speed/Caching/Network+Scrape Shield) — ver §1; badge "Missing API token" se `cloudflareAuth.token` vazio |
|
|
| `app-for-cf_analytics` | **Web analytics** | Toggle único para injectar o beacon JavaScript do Cloudflare Web Analytics (privacy-first, sem cookies) em todas as páginas; link directo para o dashboard de analytics quando activo |
|
|
| `app-for-cf_dmarc` | **DMARC management** | Gráfico (Chart.js) de volume de email pass/fail por semana/mês + tabela de fontes de envio detectadas via os relatórios DMARC que a Cloudflare recebe em nome do domínio; link "View in Cloudflare" para o dashboard |
|
|
| `app-for-cf_request-trace` | **HTTP request trace** | Formulário para simular um pedido (URL, método, protocolo, bot score, país, threat score, skip challenge) e ver que produtos/regras Cloudflare seriam aplicados — requer scope `Account.Allow Request Tracer` |
|
|
| `app-for-cf_ip-details` | **IP address details** | Consulta a Cloudflare Intel API para um IP: PTR, ASN/organização, tipo, risk types — requer `Account.Intel:Read` |
|
|
| `app-for-cf_domain-details` | **Domain details** | Idem para domínios: tipo, IPs de resolução, categorias de conteúdo |
|
|
| `app-for-cf_whois` | **WHOIS** | Consulta WHOIS via Cloudflare Intel: datas de criação/actualização, registrant, registrar, nameservers |
|
|
| (sem entrada de menu própria) **Copy Settings** | acedida a partir de um botão na página Settings | Copia todas as definições de zona de uma zona diferente da mesma conta Cloudflare para a zona actual — **irreversível**, exige confirmação explícita ("I understand...") antes de activar o botão de submissão |
|
|
|
|
Páginas exclusivas de **multisite network admin** (`settings.php?page=`):
|
|
|
|
| Slug | Título | O que faz |
|
|
|---|---|---|
|
|
| `app-for-cf_multisite-settings` | **Cloudflare** (em Network Admin → Settings) | Define um token API partilhado por toda a rede (`app_for_cf_network`), com a mesma checklist de 21 permissões do §6; cada site individual pode optar por usar o token de rede ou o seu próprio |
|
|
| `app-for-cf_multisite-r2` | **R2 (media storage)** (Network Admin) | Um único bucket R2 partilhado por todos os sites da rede, com o caminho de cada ficheiro prefixado por `{siteId}/` (ex. `cdn.site.com/50/2023/10/image.png`) — feature Pro, licenciada ao hostname do site principal da rede |
|
|
|
|
---
|
|
|
|
## 11. Free vs Pro — gate `Helper\Api::check()`
|
|
|
|
`Helper\Api::$version` / `Helper\Api::check($force = false)` (`Helper/Api.php`)
|
|
determina se a licença Premium está activa através de um **transient**
|
|
(`acf_int`) com 6 horas de validade (`21600` segundos) — não é lido de
|
|
`cfLicenseKey` directamente a cada pedido, é cacheado. `Setup::install()`
|
|
chama `Api::check(true)` (forçado) na activação do plugin.
|
|
|
|
Funcionalidades bloqueadas/degradadas no plano Free (confirmado nos
|
|
templates admin, condicional `Helper\Api::$version` ou classe CSS `pro`):
|
|
- Botão "Create rule"/"Create page rule"/"Create cache rule"/"Create user
|
|
agent rule"/"Create IP address rule" (Firewall, Rules) — sem eles, as
|
|
tabelas continuam a **listar** regras já criadas manualmente no
|
|
dashboard Cloudflare, só não permitem criar a partir do wp-admin
|
|
- Página R2 (media storage) — bloqueada mesmo com token válido
|
|
- Página Access (Zero Trust) — lista mas não gere
|
|
- "Copy from..." (Copy Settings) — botão só aparece se
|
|
`Helper\WordPress::hasOwnApiToken()` **e** implicitamente exige Pro
|
|
para ser útil em produção
|
|
- Campo "License key" só aparece se `Helper\Api::$version` já tiver
|
|
alguma licença associada (mostra o campo para trocar/renovar)
|
|
- "Block spammer IPs"/"Days that firewall rules last"/"External data
|
|
URL" (`cloudflareBlockIpsSpamClean`, `cloudflareFirewallExpireDays`,
|
|
`cfExternalDataUrl`) aparecem com classe CSS `pro` e `disabled` quando
|
|
`(int)$cloudflareAppInternal` é falso — os campos ficam visíveis mas
|
|
não editáveis
|
|
|
|
Todas as definições de zona do §1 (SSL/TLS, Speed, Caching, Network,
|
|
Scrape Shield, Bot Management/SBFM), o WAF via Managed Ruleset (§2), HSTS
|
|
(§3), Certificate Transparency/Leaked Credential Checks (§4), guest page
|
|
caching (§9), purge de cache e Turnstile CAPTCHA (§8) **funcionam no plano
|
|
Free do plugin** — não são gated, só dependem do plano Cloudflare
|
|
subjacente (Free Website vs Pro/Business), que é uma dimensão diferente.
|
|
|
|
---
|
|
|
|
## 12. Automação — WP-CLI e Cron
|
|
|
|
```bash
|
|
# Purgar cache Cloudflare (Purge Everything) via linha de comandos
|
|
wp app-for-cf purge-cache --allow-root --path=$PATH
|
|
```
|
|
|
|
Implementado em `Cli/PurgeCache.php` (comando `app-for-cf purge-cache`,
|
|
`@when after_wp_load`) — chama `Repository\Cloudflare::purgeCache()` sem
|
|
argumentos (equivalente ao botão da página "Purge cache", §10).
|
|
|
|
`Cron\Jobs::purgeCache(array $urls)` é o mecanismo interno usado por
|
|
`Base\Pub::purgeCacheByPostIds()` quando um post muda de estado
|
|
(publicado/editado) ou um comentário muda de estado — faz **chunking em
|
|
lotes de 30 URLs** por chamada à API de purge (limite da Cloudflare por
|
|
pedido), parando o loop no primeiro chunk que falhar em vez de continuar a
|
|
tentar os restantes.
|
|
|
|
---
|
|
|
|
## 13. Áreas do plugin sem config a auditar/activar (confirmado nesta sessão, `emanuelalmeida.pt`)
|
|
|
|
| Área | Estado |
|
|
|---|---|
|
|
| Cache Rules / Page Rules | 0 regras — `GET /zones/{id}/pagerules` → `count:0` |
|
|
| Access (Zero Trust) | Não configurado, fora de âmbito nesta sessão — funcionalidade real do plugin, ver §10 |
|
|
| Turnstile CAPTCHA | Site key existe mas desligada no plugin (`cfTurnstile: ["0"]`) — infra pronta se decidido substituir reCAPTCHA; ver estrutura completa das 13 sub-chaves no §8 |
|
|
| Workers proxy (`cfProxy`) | `{image: off, url: off}` |
|
|
| R2 (media storage) | `cfR2Bucket.media` vazio, `cfExternalDataUrl` vazio — nunca activado neste site; requer licença Pro (§11) |
|
|
| DMARC/SPF/DKIM (`Dmarc.php`) | **Auditar via DNS público directo** (`dig TXT`), nunca precisa de token Cloudflare — são registos públicos por desenho; a página DMARC do plugin (§10) é sobre os relatórios agregados que a Cloudflare recebe, não sobre editar os próprios registos DNS |
|
|
| Web Analytics (beacon JS) | Confirmar por ausência/presença de `cloudflareinsights`/`beacon.min.js` no HTML servido, não por option — a página Web Analytics (§10) tem toggle próprio fora de `wp_options` (via API, não confirmado nesta sessão se lê de zona ou de conta) |
|
|
| EasyConfig (`setEasyMode()`) | Aplica tudo em bloco (lista exacta no §1) — preferir aplicar definição a definição para manter controlo e rasto de decisão |
|
|
| Licença Pro (`cfLicenseKey`) | Vazia — plugin a correr em modo Free; ver §11 para o que fica indisponível |
|
|
|
|
---
|
|
|
|
## Fonte
|
|
|
|
`CONFIG-Plugins-Referencia.md` §1 (App for Cloudflare®) — achados originais
|
|
de HSTS/WAF/DMARC, credenciais de sessão. `BUNDLE-Excelencia-WP.md` §2.2
|
|
(Performance) e §2.4 (GEO — bots de IA, achado completo do
|
|
`is_robots_txt_managed` e dos 7 campos de Bot Management via API directa).
|
|
Ambos em `Hub/04-Stack/02.04-Sistemas/71.Seguranca/`, piloto
|
|
`emanuelalmeida.pt`, sessão 16-08-2026.
|
|
|
|
**Expansão desta sessão (16-08-2026):** leitura completa do código-fonte
|
|
do plugin `app-for-cf` v1.10.0 via SSH (`server`, 61 ficheiros PHP,
|
|
11.309 linhas) — não apenas os ficheiros tocados na auditoria pontual
|
|
original. Ficheiros lidos na íntegra: `app-for-cf.php` (bootstrap),
|
|
`Setup.php` (schema de `wp_options`), `Repository/Cloudflare.php` (2178
|
|
linhas — lista completa de 52 definições de zona + `setEasyMode()` +
|
|
lógica de leitura/escrita), `Admin/Template/Settings.php` (766 linhas —
|
|
UI completa, scopes de token, Turnstile), `Admin/Base/Admin.php` (menu,
|
|
14 páginas), `Helper/Api.php` (gate Free/Pro), `Cron/Jobs.php`,
|
|
`Cli/PurgeCache.php`, e os 14 templates individuais em `Admin/Template/`
|
|
(`Firewall.php`, `R2.php`, `Access.php`, `Rules.php`, `Analytics.php`,
|
|
`Dmarc.php`, `RequestTrace.php`, `IpDetails.php`, `DomainDetails.php`,
|
|
`Whois.php`, `CachingGuestPage.php`, `Caching.php`, `Cache.php`,
|
|
`CopySettings.php`, `MultisiteR2.php`, `MultisiteSettings.php`) e trechos
|
|
relevantes de `Base/Pub.php` (657 linhas — guest page caching, preload,
|
|
purge). Confirmado ao vivo com `wp option get app_for_cf --format=json`
|
|
em `emanuelalmeida.pt` que as 18 chaves de `wp_options` batem certo com
|
|
`Setup::defaults()`. Nenhuma escrita feita em produção durante esta
|
|
expansão — só leitura de código-fonte e `wp option get`.
|