Files
claude-plugins/wordpress/skills/mcp-insert-headers-footers/SKILL.md
T

8.5 KiB

name, description, layer
name description layer
mcp-insert-headers-footers MCP dedicado multi-site (node stdio, ligação `insert-headers-footers` em ~/.omp/agent/mcp.json) para ler e escrever os 3 blocos globais de código (header/body/footer) do plugin Insert Headers and Footers (agora rebrandeado "WPCode Lite", slug `insert-headers-and-footers`) via WP-CLI/SSH. ⚠️ Superfície de risco real — estes 3 blocos injectam HTML/JS/CSS arbitrário em TODAS as páginas do site (produção incluída); uma escrita mal formada pode partir o site inteiro ou abrir um vector XSS. Site é um parâmetro em cada tool. Usar quando "insert headers and footers", "wpcode lite", "header footer mcp", "injectar script no site todo", "código global wordpress", "meta pixel site inteiro", "gtm noscript global", "ihaf mcp". wiki

/mcp-insert-headers-footers — MCP dedicado multi-site ao Insert Headers and Footers (WPCode Lite)

Projecto em /media/ealmeida/Dados/Dev/mcp-insert-headers-footers/ (TypeScript, SDK MCP oficial, stdio). Sem código PHP novo no WordPress — cada tool executa wp eval com um snippet PHP estático (nunca dados do utilizador interpolados no comando) via ssh server sobre o WP-CLI já instalado. site é um parâmetro em cada tool, não uma ligação fixa — o plugin está confirmado active (WPCode Lite 2.3.8) nos 8 sites reais do bundle.

⚠️ Superfície de risco

Este plugin injecta os 3 blocos em todas as páginas de todo o site, via wp_head, wp_body_open e wp_footer. Não há "sandbox" nem preview automático — o que estiver gravado sai directamente no HTML servido a todos os visitantes assim que a cache de página for purgada (ou imediatamente, se não houver cache activa). Riscos concretos:

  • Quebra visual/funcional site-wide — uma tag HTML não fechada, um <script> malformado, ou CSS inline quebrado no bloco body (que corre logo a seguir a <body>) pode desalinhar ou esconder o site inteiro para todos os visitantes.
  • Vector XSS real — qualquer conteúdo aqui corre sem sanitização nenhuma no frontend (echo wp_unslash($code) directo, sem esc_html/wp_kses). Nunca aceitar conteúdo de origem não confiável para estes blocos.
  • Perda de conteúdo — a escrita é substituição total do bloco, não merge. Ler sempre primeiro com ihaf_get_blocks; se o bloco já tiver código em produção (ex. Meta Pixel + GTM noscript em descomplicar), o conteúdo completo desejado (antigo + novo) tem de ser fornecido explicitamente.

A tool de escrita (ihaf_set_block) está marcada destructiveHint:true e a sua descrição já inclui este aviso — mas o agente que a chama é responsável por: (1) ler o bloco antes de escrever, (2) testar em starter (staging) sempre que possível antes de descomplicar (produção), (3) purgar cache de página e verificar o site visualmente depois de escrever.

Sites conhecidos

Chamar ihaf_list_sites para a lista actual com path e nota de estado. Todos os 8 sites do bundle verificados active (WPCode Lite 2.3.8) ao vivo em 19-08-2026: descomplicar (produção — bloco body já em uso: Meta Pixel + GTM noscript, não sobrescrever sem ler primeiro), emanuelalmeida, starter (os 3 blocos vazios — site preferencial para testes), ccv, care, ecommerce-demo, e-commerce, ecommerce. Também aceita um path absoluto directamente (/home/ealmeida/<site>) para sites fora desta lista.

Tools (4)

Tool Read-only Uso
ihaf_list_sites sim Aliases conhecidos, path WP, nota de estado
ihaf_get_plugin_status sim Instalado/activo + versão — chamar antes se não tiver a certeza de que o plugin está activo nesse site
ihaf_get_blocks sim Os 3 blocos (header/body/footer) no texto lógico exacto que é servido ao frontend, mais headersFootersMode informativo. Chamar SEMPRE antes de ihaf_set_block
ihaf_set_block não — destructiveHint:true Substitui por inteiro UM dos 3 blocos (block: header|body|footer). content é o texto final completo, sem escaping adicional (o MCP trata do wp_slash() internamente)

Todas as tools exigem site como primeiro parâmetro.

Mapeamento de dados (a única documentação destes 3 blocos)

Não há skill de conhecimento separada para este plugin — este é o mapeamento completo.

Os 3 blocos vivem em 3 wp_options planas (não uma option única, não uma tabela custom):

Bloco Option Hook de output Posição no HTML
header ihaf_insert_header wp_head Dentro de <head>
body ihaf_insert_body wp_body_open (prioridade 1) Logo a seguir à abertura de <body>
footer ihaf_insert_footer wp_footer Antes de </body>

Código fonte confirmado (includes/global-output.php): cada option é lida com get_option() cru e impressa com echo wp_unslash( $code ), sem qualquer sanitização. Ficam vazias por omissão (get_option() devolve ''), o output é simplesmente ignorado se empty( trim( $code ) ). Também são ignoradas em is_admin(), is_feed(), is_robots(), is_trackback().

⚠️ Gotcha crítico de formato — slashing, não JSON

Diferente do gotcha do WP Fastest Cache (JSON string vs option tipada), aqui o problema é slashing do WordPress, não JSON. O ecrã de admin do plugin grava directamente a partir de $_REQUEST (includes/admin/pages/class-wpcode-admin-page-headers-footers.php):

update_option( 'ihaf_insert_header', $_REQUEST['ihaf_insert_header'] );

Como o WordPress aplica addslashes() globalmente a todos os superglobais logo no arranque (wp_magic_quotes()), o valor gravado em wp_options fica sempre "slashed" — aspas e backslashes escapados. No frontend, o output faz sempre wp_unslash( $code ) antes de imprimir. Ou seja: a option em repouso na base de dados nunca é o texto lógico da página — é sempre esse texto com addslashes() aplicado.

Confirmado ao vivo em produção (19-08-2026), bloco body:

BD (raw):     style=\"display:none\"
Frontend:     style="display:none"

Por isso este MCP nunca usa wp option get/update em bruto sobre estas 3 keys. Usa sempre wp eval com as funções nativas wp_unslash() (leitura) e wp_slash() (escrita) — nunca reimplementa addslashes/stripslashes em TypeScript. ihaf_get_blocks devolve sempre o texto lógico (pós-wp_unslash, o que realmente sai no HTML); ihaf_set_block recebe o texto lógico desejado e aplica wp_slash() do lado do servidor antes de update_option(). Sem este passo, qualquer backslash literal no conteúdo (regex JS, \n em atributos, etc.) seria corrompido no próximo wp_unslash() do frontend.

Qualquer MCP futuro sobre uma option que seja alimentada a partir de $_REQUEST/formulário admin deve verificar primeiro se o plugin em causa depende deste padrão de slashing implícito do WordPress antes de escolher wp option get/update directo.

Segurança

Allowlist fixa das 3 option keys (src/wpcli.ts, BLOCK_OPTION_KEYS) — nunca wp option update genérico sobre uma chave arbitrária. Conteúdo sempre via base64 em stdin, nunca interpolado no comando SSH remoto; o único dado interpolado directamente no snippet PHP é o nome da option, que vem de uma allowlist fixa de 3 valores (não de input do utilizador), tal como o padrão já usado em mcp-wpfc. A escrita também invalida a page cache do próprio plugin quando disponível (wpcode_clear_all_plugins_page_cache('global')), mas não purga WP Fastest Cache/Cloudflare — isso é responsabilidade de quem chama a tool (ver mcp-wpfc/mcp-cloudflare-app).

Verificação

Construído e testado ponta-a-ponta 19-08-2026: ihaf_get_plugin_status e ihaf_get_blocks confirmados contra produção (descomplicar) — bloco body com Meta Pixel + GTM noscript lido correctamente já unslashed, idêntico ao confirmado por leitura SSH directa fora do MCP (wp_unslash(get_option(...))). Write round-trip testado em starter (staging, blocos vazios): escrita de conteúdo com aspas e backslash duplo via ihaf_set_block, releitura via ihaf_get_blocks confirmou o texto lógico exacto preservado (aspas e backslashes intactos), depois revertido para "" e confirmado por leitura SSH directa (get_option() == "") e por ihaf_get_blocks limpo, sem alterar o estado original do site.

Skills relacionadas

  • mcp-wpfc — purga de page cache local, complementar depois de alterar estes blocos.
  • wp-cli — padrões gerais de WP-CLI multi-site usados como base deste MCP.