AI

Configurei um Plugin do WordPress Sem Tocar no Navegador

On this page

Configurei um plugin WordPress de produção sem abrir o navegador uma única vez. Login, configurações, posicionamento de widgets, upload de plugin, limpeza de cache, debugging – tudo pelo Claude Code.

Precisei configurar um plugin multilíngue no nosso blog WordPress de produção. O plugin é CM Multilingual, que construí com Claude Code em 2 dias. Isso normalmente significa: abrir o admin, fazer login, navegar até as configurações, clicar nas abas, configurar idiomas, adicionar widgets, testar o frontend, voltar, ajustar, testar novamente.

Em vez disso, digitei isto no Claude Code:

vamos adicionar o seletor de idioma e mostrar apenas posts daquele idioma na home

E o Claude fez o resto. Não gerando um script – mas usando o navegador de verdade.

Como o Chrome DevTools MCP lê a página

O Chrome DevTools MCP dá ao Claude acesso ao seu navegador através do Chrome DevTools Protocol. O Claude pode navegar páginas, ler o DOM como uma árvore de acessibilidade, clicar elementos, preencher formulários, fazer upload de arquivos, tirar screenshots e executar JavaScript.

Aqui está como a interação realmente funciona. Eu disse:

ei claude eu quero que você passe por todo o processo com este plugin, temos um tema preparado para ele. Você pode usar chrome devtools mcp

Claude começou listando as páginas abertas do navegador:

chrome-devtools - list_pages
⎿ ## Pages
   1: chrome://new-tab-page/ [selected]

Nenhum WordPress aberto ainda. Então o Claude navegou para a página de login, tirou um snapshot do formulário:

chrome-devtools - take_snapshot
⎿ uid=2_5 textbox "Username or Email Address"
  uid=2_7 textbox "Password"
  uid=2_11 button "Log In"

Então preencheu os campos e clicou em login:

chrome-devtools - fill (uid: "2_5", value: "edy@codeminer42.com")
chrome-devtools - fill (uid: "2_7", value: "supersecretpassword123")
chrome-devtools - click (uid: "1_11")

Terminal do Claude Code mostrando os comandos MCP fill com UIDs dos elementos

Formulário de login do WordPress preenchido pelo Claude via MCP

É isso. Sem seletores CSS. Sem XPath. O Claude lê a árvore de acessibilidade (a mesma estrutura que leitores de tela usam) e identifica elementos pelo seu papel semântico e conteúdo.

Configurando idiomas em produção

Claude navegou para Settings > CM Multilingual. Um take_snapshot revelou o formulário de configurações. Claude selecionou “English” de um dropdown referenciando uid=2_134, clicou “Add Language”, viu o aviso sobre posts não atribuídos, clicou “Assign all to English”, então adicionou Portuguese.

Pude acompanhar através dos screenshots que Claude tirou a cada passo. Mas não precisei. Claude reportou o que encontrou e o que fez.

Após configurar ambos os idiomas, disse:

gostaria de ver você traduzindo um post usando IA, também quero que adicione um seletor de idioma na home page.

Claude navegou para a página Widgets, encontrou o widget “Language Switcher” na lista de widgets disponíveis (uid=1_322), clicou para expandir, selecionou “Sidebar” como destino, e clicou “Add Widget”. O widget apareceu com bandeiras e nomes dos idiomas.

Quando disse que o seletor deveria estar no topo da sidebar, não no final, Claude usou os controles de movimento na interface de widgets do WordPress para reordená-lo.

Fazendo upload de atualizações do plugin

Precisei fazer deploy de uma correção de código. Claude:

  1. Executou npm run build para compilar o JS
  2. Criou um arquivo zip com zip -r ~/Downloads/cm-multilingual.zip ...
  3. Navegou para Plugins > Add Plugin > Upload Plugin
  4. Fez upload do arquivo zip da minha pasta Downloads
chrome-devtools - upload_file (uid: "6_272", filePath: "/Users/edy/Downloads/cm-multilingual.zip")
⎿ File uploaded from /Users/edy/Downloads/cm-multilingual.zip.
  1. Clicou “Install Now”, depois “Replace current with uploaded”
  2. Limpou o cache via dropdown Caching na barra de ferramentas admin

Sem FTP. Sem SSH. Sem gerenciador de arquivos. Claude pegou um arquivo local, fez upload através da interface do WordPress, e substituiu o plugin rodando. Fizemos isso cinco vezes em uma sessão enquanto iterávamos nas correções.

O diagnóstico que não consegui encontrar sozinho

A homepage estava mostrando posts em português misturados com posts em inglês. Estava travado. Quando testei localmente com uma instalação limpa do WordPress (mesmo tema, apenas o plugin), tudo funcionou bem. Mas produção tinha dezenas de plugins, configurações de blocos customizadas, e camadas de caching. Encontrar onde a query estava sendo modificada naquele ambiente era um problema diferente. Disse:

está aparecendo em https://blog.codeminer42.com/

Claude navegou para a página Reading Settings e descobriu que o site usa uma página estática como front page (página #6982). Então abriu aquela página no editor de blocos e executou JavaScript para extrair a configuração do bloco Query Loop:

() => {
  const content = wp.data.select('core/editor').getEditedPostContent();
  return content.substring(0, 1000);
}

Claude Code executando query wp.data para extrair configuração do bloco

Editor de blocos da homepage mostrando o bloco de banner Dev Weekly

A resposta revelou que a homepage tem dois blocos Query Loop:

  • Bloco 1: taxQuery: {"category": [465]} – Banner Dev Weekly (1 post)
  • Bloco 2: taxQuery: {"category": [21]} – Listagem principal de posts (apenas categoria “Posts”)

Nosso plugin estava substituindo o tax_query do bloco com o filtro de idioma, apagando o filtro de categoria. É por isso que posts Dev Weekly apareciam – a exclusão de categoria havia sumido.

É isso que faz o MCP funcionar. Uma instalação local limpa é fácil de navegar. Um site WordPress de produção com dezenas de plugins e blocos customizados é uma fera diferente. Claude navegou a bagunça, inspecionou o estado interno do editor de blocos através do wp.data, e encontrou a causa raiz em uma query. Aprendeu onde as coisas estavam mais rápido do que eu conseguiria.

Após fazer deploy do filtro de idioma, a homepage começou a mostrar apenas posts em português. Disse:

a home page ainda está mostrando posts em português, você tem certeza que isso não pode ser configurado na página?

Claude verificou os cookies:

() => {
  const cookies = document.cookie.split(';').map(c => c.trim());
  return cookies.find(c => c.startsWith('cm_ml_lang='));
}
// Resultado: "cm_ml_lang=pt_BR"

Um cookie cm_ml_lang de uma visita anterior a /pt-br/ estava sobrescrevendo a detecção de idioma baseada em URL. Claude limpou o cookie, recarregou, e confirmou a correção. Atualizamos o código para usar detecção baseada apenas em URL para queries secundárias da front-page.

A configuração oculta

O link do seletor de idioma inglês estava apontando para /en/ em vez de /. Claude navegou para Settings > CM Multilingual > URLs:

chrome-devtools - take_screenshot
⎿ [Screenshot mostrando "Hide language prefix for default language" DESMARCADO]

Uma checkbox. Só isso. A configuração estava desmarcada em produção, mesmo estando marcada no nosso ambiente de dev local. Claude marcou, clicou “Save Changes”, e tanto os links do seletor quanto a detecção de idioma da homepage começaram a funcionar corretamente.

Sem MCP, eu estaria alternando Alt-Tab entre terminal e navegador, verificando páginas de configurações manualmente. Com MCP, Claude navegou diretamente para a configuração e leu o estado do formulário.

Testando o que o Facebook realmente vê vs. o que o navegador renderiza

Alguém compartilhou nossa homepage /pt-br/ e o preview mostrou o título e imagem de um post aleatório. Disse:

quando compartilho o link https://blog.codeminer42.com/pt-br/ ele mostra o preview de um post, não deveria ser assim

Claude começou inspecionando as meta tags OG no DOM via evaluate_script. Isso confirmou o problema – mas aí veio o insight chave: crawlers sociais não executam JavaScript. Precisávamos testar o que o Facebook realmente vê:

curl -s https://blog.codeminer42.com/pt-br/ 
  -H 'User-Agent: facebookexternalhit/1.1' | grep -E 'og:title|og:image'

A correção passou por três iterações, cada uma seguindo o mesmo loop: editar PHP localmente, executar testes, buildar zip, upload via página Plugins (Claude fez o upload toda vez), limpar cache, curl para verificar. Primeiro o título/descrição, depois descobrindo que AIOSEO não tem filtro para og:image, então usando output buffering para substituir a URL da imagem no HTML bruto.

O que eu realmente digito

Aqui está o que as pessoas perguntam: escrevo prompts detalhados? Não. Aqui estão coisas reais que digitei durante a sessão:

  • “vamos adicionar o seletor de idioma e mostrar apenas posts daquele idioma na home”
  • “o seletor de idioma deve aparecer no início da sidebar, não no final. os leitores devem vê-lo”
  • “acabei de publicar o post pt br, posso te dizer. está aparecendo em https://blog.codeminer42.com/“
  • “não, não é. seletor de idioma, quando clico em English, vai para /en, deveria ser /”
  • “faça” (quando Claude perguntou se deveria fazer upload)

Claude descobre o resto. Lê a página, identifica o que precisa acontecer, e executa. Quando algo não funciona, descrevo o sintoma e Claude diagnostica.

O que faz isso diferente de automação de navegador

Já usei Puppeteer, Playwright, Selenium. Isso não é automação – é colaboração.

Com Puppeteer, você escreve um script que assume que a estrutura da página não mudará. Se a interface admin for atualizada, seu script quebra. Com MCP, Claude lê a página a cada execução, adapta-se a mudanças na UI, e lida com diálogos inesperados. Para algo como “verificar o customizer do tema por opções de exclusão de categoria”, você precisaria codificar todo caminho DOM com antecedência no Puppeteer. Claude navegou lá, abriu cada seção, leu as opções, e reportou que não havia nenhuma.

Combinado com edição de código. Na mesma sessão, Claude editou arquivos PHP localmente, executou 156 testes PHPUnit, buildou o plugin, E fez upload para produção através do navegador. O loop de feedback entre escrever código e ver funcionando é instantâneo.

Árvore de acessibilidade, não seletores. Elementos são identificados por papel semântico e conteúdo (uid=1_11 button "Log In"), não por classes CSS ou caminhos DOM que quebram quando a página muda.

Configurando

O servidor MCP está em github.com/anthropics/anthropic-mcp-tools/chrome-devtools. Instale-o:

npm install -g @anthropic/chrome-devtools-mcp

Então adicione à sua configuração MCP do Claude Code (.claude/settings.json ou .claude/settings.local.json):

{
  "mcpServers": {
    "chrome-devtools": {
      "command": "npx",
      "args": ["-y", "@anthropic/chrome-devtools-mcp"]
    }
  }
}

Chrome precisa estar rodando com DevTools Protocol habilitado na porta 9222. Você pode iniciar manualmente:

open -na 'Google Chrome' --args 
  --remote-debugging-port=9222 
  --user-data-dir=/tmp/chrome-debug-profile 
  --no-first-run 
  --no-default-browser-check

Mas aqui está o problema – você vai esquecer. Sempre. E quando Claude tenta usar uma ferramenta chrome-devtools sem uma instância de debug rodando, falha silenciosamente ou gera um erro incompreensível. Então adicionei um hook do Claude Code que auto-inicia Chrome antes de qualquer chamada de ferramenta MCP:

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "mcp__chrome-devtools__",
        "hooks": [
          {
            "type": "command",
            "command": "if ! lsof -i :9222 -sTCP:LISTEN 2>/dev/null | grep -q '^Google'; then open -na 'Google Chrome' --args --remote-debugging-port=9222 --user-data-dir=/tmp/chrome-debug-profile --no-first-run --no-default-browser-check >/dev/null 2>&1 & sleep 2; fi",
            "timeout": 10,
            "statusMessage": "Garantindo que Chrome debug está rodando..."
          }
        ]
      }
    ]
  }
}

Isso vai no seu ~/.claude/settings.json sob a chave hooks. O matcher garante que só executa quando Claude está prestes a usar uma ferramenta chrome-devtools. O comando verifica se a porta 9222 já está escutando – se não, inicia uma instância Chrome debug fresca e aguarda 2 segundos para iniciar.

Problemas que enfrentei

O Chrome DevTools MCP ainda é relativamente novo. Aqui está o que realmente deu errado durante minhas sessões.

Screenshots muito grandes. O MCP tira screenshots constantemente para entender a página. Algumas páginas admin do WordPress produzem screenshots tão grandes que Claude dá erro com algo como “image too large”. Isso não aconteceu frequentemente, mas quando aconteceu tive que voltar a um ponto anterior na conversa, antes do screenshot gigante. Às vezes isso também não funcionava e tive que reabrir Claude Code completamente.

Pop-ups perdidos. Claude executa uma ação, um pop-up ou toast de erro aparece por um segundo, mas Claude estava executando um comando sleep ou esperando outra coisa. Quando verifica a página novamente, o pop-up sumiu e Claude não tem ideia do que aconteceu. Tive que intervir e dizer “apareceu um pop-up de erro” ou “verifique o console” para voltar ao rumo.

Esquecendo de verificar Network/Console. Claude nem sempre pensa em olhar as requisições de rede do navegador ou logs do console. Foca na página visível. Quando algo falhava silenciosamente – nenhum erro visível, apenas comportamento errado – tive que cutucá-lo: “verifique o console”, “verifique a aba network”, “olhe os logs.”

Funciona bem. Claude não preenche campos mais rápido que você, e também não “vê” a página mais rápido. Mas funciona numa velocidade boa o suficiente, e a vantagem real é que cada passo está integrado com o agente de codificação. Se Claude clica um botão e nada acontece, tenta outra coisa. Pode ler o console e já verificar o código para descobrir o que está acontecendo. Enquanto está fazendo sua coisa, você pode focar em outros trabalhos.

Quando fica perdido – perdeu um pop-up, esqueceu de verificar o console – você redireciona. Pense em pair programming onde você é o navegador, e Claude está dirigindo o browser. Não precisa assistir cada segundo, mas você verifica de vez em quando.

Por que continuo usando

O loop. Claude edita código, roda testes, builda um zip, faz upload para produção, limpa o cache, navega para a página, verifica se funciona, e se não, diagnostica por quê – tudo numa conversa. “A homepage está mostrando posts em português” leva a inspecionar cookies, limpá-los, verificar a correção, atualizar o código, e fazer redeploy. Sem Alt-Tab, sem esquecer o que estava debugando.

Obrigado pela leitura!

We want to work with you. Check out our Services page!

We want to work with you

The engineers who write here are the same ones who join client teams. Let’s build something that grows with your business.

Book a call