Virtus Design
Voltar ao Blog
Desenvolvimento

Arquitetura WordPress Headless com Next.js: REST API, ISR e Application Passwords

A arquitetura técnica completa de um site WordPress Headless com Next.js. Application Passwords, ISR de 5 minutos, _embed=true e tolerância a falhas.

Arquitetura WordPress Headless com Next.js: REST API, ISR e Application Passwords

TL;DR

Conectar Next.js no WordPress em cinco minutos é fácil. Manter em produção, com performance, segurança e tolerância a falhas, é outra história. A arquitetura que adotamos em todos os sites do portfólio Virtus combina cinco peças: Application Passwords para autenticação, REST API com _embed=true contra N+1, ISR de 5 minutos como sweet spot de cache, AbortSignal de 10 segundos para tolerar lentidão do CMS, e cache tags prontas para revalidação on-demand. Cada decisão tem motivo. Cada motivo tem código. Este artigo detalha tudo, com tipos TypeScript completos.

Os três papéis da arquitetura

Em uma arquitetura WordPress headless com Next.js bem desenhada, três sistemas têm responsabilidades claras e bem delimitadas. Confundir os papéis é o erro mais comum dos primeiros projetos.

WordPress (CMS): é a fonte da verdade. Armazena posts, páginas, mídia, taxonomias, usuários e metadados. Não renderiza HTML para o público, apenas serve dados via REST API. Pode ficar em hospedagem WordPress padrão (Hostinger, SiteGround, Kinsta), em um subdomínio interno como wp.cliente.com.br.

Next.js (Server): é a aplicação que consome a API e renderiza páginas. Roda em uma plataforma serverless (Vercel é o padrão), gera HTML no edge a partir do conteúdo retornado pelo WordPress. É aqui que vive a interface visual, o roteamento, o SEO técnico e a lógica de cache.

Edge / CDN: entrega o HTML estático cacheado a partir do nó mais próximo do usuário. ISR garante que esse cache seja revalidado periodicamente sem que ninguém precise fazer deploy. É o que torna o site rápido em qualquer lugar do mundo.

Autenticação: Application Passwords (nunca senha de usuário)

O WordPress oferece desde a versão 5.6 um recurso chamado Application Passwords. São tokens longos, gerados no painel administrativo, que funcionam como senha apenas para chamadas de API. A senha do usuário humano nunca é exposta.

Por que isso importa: se um Application Password vazar, você revoga ele direto no painel sem afetar o login do usuário. Se a senha de usuário vazar, todo o painel e todos os logins ficam comprometidos. A diferença entre os dois modelos é a diferença entre uma chave de cofre e uma chave mestra.

O fluxo de autenticação para a REST API usa Basic Auth com o Application Password no lugar da senha. Em código:

function getAuthHeaders(): HeadersInit {
const user = process.env.WP_USER;
const pass = process.env.WP_APP_PASSWORD;
if (!user || !pass) return {};
const token = Buffer.from(`${user}:${pass}`).toString("base64");
return { Authorization: `Basic ${token}` };
}

Erro mais comum: commitar credenciais no Git. As variáveis WP_USER e WP_APP_PASSWORD ficam exclusivamente em .env.local (ignorado pelo Git) e na configuração de variáveis de ambiente da plataforma de deploy. Vazar credenciais em commit é incidente de segurança que exige rotação imediata.

lib/wordpress.ts: o módulo único de integração

Em todos os projetos do nosso portfólio, a integração com a REST API do WordPress mora em um único arquivo: src/lib/wordpress.ts. Centralizar facilita testes, evita duplicação e padroniza tratamento de erro. Nenhum componente fala diretamente com a API; tudo passa pelo módulo.

O módulo expõe funções nomeadas por intenção: getPosts(page, perPage), getPostBySlug(slug), getCategories(), getPostsByCategory(categoryId). Cada função retorna tipos TypeScript fortes (WPPost, WPCategory, WPMedia) que refletem a forma real do retorno da REST API com _embed=true.

Esses tipos não são gerados automaticamente. São escritos à mão a partir do que a API retorna, o que dá controle total e evita dependências quebradiças com geradores de schema. Em troca, você atualiza o tipo quando o WordPress muda algo.

Checklist: o que o módulo lib/wordpress.ts precisa expor

  • Funções de leitura para todos os recursos consumidos (posts, páginas, categorias, mídia, menus)

  • Tipos TypeScript explícitos para cada recurso, refletindo a forma real do retorno

  • Helpers utilitários (stripHtml, getFeaturedImageUrl, getCategoryNames) que simplificam o uso nos componentes

  • Tratamento de erro consistente (try/catch com fallback para [] ou null)

  • Configuração centralizada de cache, timeout e autenticação

ISR de 5 minutos: o sweet spot de cache

Incremental Static Regeneration é o mecanismo do Next.js que serve páginas como HTML estático e revalida o cache em segundo plano após um intervalo configurado. Em vez de gerar a página em cada request (slow) ou só no build (stale), você gera no primeiro acesso e revalida no intervalo definido.

O intervalo certo depende do trade-off entre frescor de conteúdo e custo de revalidação. Em sites institucionais com edição diária, usamos 5 minutos como padrão. É frequente o suficiente para que correções de copy apareçam rápido, e infrequente o suficiente para que o cache faça seu trabalho:

const res = await fetch(url, {
headers: getAuthHeaders(),
next: { revalidate: 300 }, // 300 segundos = 5 minutos
});

Em sites de e-commerce ou notícias com publicação frequente, o intervalo pode cair para 60 segundos. Em sites com edição rara (institucional puro, sem blog ativo), pode subir para 1 hora. O número não é dogma, é uma decisão baseada na frequência real de mudança do conteúdo.

_embed=true: eliminando N+1 queries

Por padrão, a REST API do WordPress retorna em /posts apenas o ID da imagem destacada, do autor e das categorias. Se você quiser o nome do autor, precisa fazer uma segunda requisição em /users/{id}. Se quiser a URL da imagem, outra em /media/{id}. Se quiser o nome da categoria, mais uma em /categories/{id}.

Em uma listagem de 12 posts, isso multiplica para dezenas de requisições. É o clássico problema N+1, e ele destrói a performance.

O parâmetro _embed=true resolve. Com ele, a API retorna todos os recursos relacionados embutidos no JSON do post, em uma única resposta. O tamanho do payload sobe um pouco, mas a latência cai drasticamente:

fetchWP<WPPost[]>("/posts", {
page: String(page),
per_page: String(perPage),
_embed: "true",
});

O retorno passa a ter um campo _embedded com sub-objetos como wp:featuredmedia, wp:term e author. Helpers como getFeaturedImageUrl(post) abstraem o caminho até esses dados.

Timeouts e fallbacks: protegendo a build de CMS lento

Em produção, o WordPress eventualmente fica lento. Hospedagem sobrecarregada, plugin pesado, query SQL ineficiente. Sem proteção, uma página do Next.js pode travar esperando 30 segundos a resposta da API, e isso reflete em timeout no usuário, falha de revalidação e até build quebrada.

A defesa é um AbortSignal.timeout() em todas as chamadas:

const res = await fetch(url, {
headers: getAuthHeaders(),
next: { revalidate: 300 },
signal: AbortSignal.timeout(10_000), // 10 segundos
});

Se o WordPress não responder em 10 segundos, a requisição é abortada. O try/catch no chamador retorna um valor neutro ([] ou null) e a página continua renderizando o que conseguiu, sem travar o usuário.

Erro mais comum: deixar o timeout default do fetch (que é infinito). Em ambiente serverless, isso consome o limite de execução da função e gera cobrança extra na plataforma.

Cache tags: deixando webhook pronto

ISR de 5 minutos resolve a maioria dos casos. Mas para conteúdo de alta importância que precisa atualizar imediatamente após edição, o ideal é revalidar on-demand via webhook do WordPress.

O Next.js suporta isso nativamente com cache tags. Cada chamada à API recebe uma tag, e um endpoint do Next dispara revalidateTag quando o WordPress envia um webhook após salvar um post:

fetchWP<WPPost[]>("/posts", params, ["wp-posts"])
// no route handler:
revalidateTag("wp-posts");

A maioria dos projetos do nosso portfólio começa só com ISR de 5 minutos e adiciona webhook quando há demanda específica. Mas a estrutura está pronta no lib/wordpress.ts desde o primeiro dia, o que evita refactor depois.

Próximos passos

Esta arquitetura é a base sobre a qual construímos todos os sites Next.js + WordPress do nosso portfólio. Os próximos artigos da série detalham camadas que ficam em cima desta: renderização de blocos Gutenberg em Server Components, otimização de Core Web Vitals e SEO programático em Next.js 16. Se você ainda não viu, comece pelo artigo de visão estratégica para entender quando esta arquitetura faz sentido.

Quer aplicar este modelo no seu projeto? Fale com a Virtus Design. Construímos sites WordPress headless com Next.js do zero, ou migramos sites existentes preservando URLs, ranking e fluxo editorial. Conheça também o portfólio completo de serviços em desenvolvimento, design e SEO.

Perguntas Frequentes

Por que ISR de 5 minutos e não SSR puro ou SSG puro?
SSR puro renderiza em cada request, o que perde o ganho de cache do edge. SSG puro só atualiza no build, o que exige rebuild a cada edição (lento e caro). ISR é o meio termo: HTML estático servido do edge, revalidado em segundo plano após o intervalo. Em conteúdo editorial, 5 minutos equilibra frescor com eficiência.
Posso usar GraphQL (WPGraphQL) ao invés da REST API?
Sim. WPGraphQL é uma alternativa válida e em casos específicos (queries muito complexas, muitos relacionamentos) chega a ser mais eficiente. Para a maioria dos sites institucionais, a REST API nativa do WordPress é suficiente, mais simples e não exige plugin adicional no CMS.
Como o site se comporta se o WordPress cair?
As páginas que já estão no cache do edge continuam sendo servidas normalmente, mesmo com o WordPress fora do ar. Apenas conteúdo novo ou páginas ainda não geradas falham. É uma camada extra de resiliência que o modelo monolítico tradicional não tem.
É seguro expor o WordPress publicamente para o front-end consumir?
Sim, desde que o painel administrativo tenha as proteções padrão (2FA, limite de tentativas de login, atualizações em dia). A REST API só expõe dados públicos por padrão. Application Passwords adicionam camada de autenticação para endpoints privados sem comprometer credenciais de usuário.
Preciso de servidor dedicado para o WordPress nesta arquitetura?
Não. Como o WordPress só atende requisições do Next.js (durante revalidações de cache) e não usuários finais, a carga é muito menor. Hospedagem WordPress padrão atende sites com até 100 mil visitas mensais sem ajustes especiais.
V

Virtus Design

Transformamos negócios em marcas digitais extraordinárias com estratégia, design e tecnologia.

Artigos relacionados