Headless Starter Kit: guia completo
Instalar, configurar e implantar o Headless Starter Kit: plugin WordPress e starter Next.js 15 chave na mão para passar o WooCommerce a headless.
Este guia cobre a instalação, a configuração e a utilização completa do Headless Starter Kit, o plugin WordPress que transforma a sua loja WooCommerce em comércio headless, acompanhado de um starter Next.js 15 chave na mão.
A quem se destina este guia. Programador, agência ou comerciante técnico que quer passar um WooCommerce existente para headless sem reinventar a autenticação, o carrinho e o checkout. Tem de estar à vontade com a linha de comandos, o Node.js e alguma configuração de servidor se escolher o Hetzner.
Visão de conjunto
O Headless Starter Kit apresenta-se em dois entregáveis distribuídos na mesma compra:
- O plugin WordPress (ZIP a carregar em
/wp-admin/plugins.php) que expõe do lado do backend: autenticação JWT, API de carrinho, ponte de checkout, endpoint de configuração público, webhooks ISR e CORS estrito. - O starter Next.js 15 (ZIP descarregável a partir da administração do WordPress depois de o plugin estar ativo e configurado) que contém um projeto Next.js completo com páginas inicial, listagem, ficha de produto ISR, carrinho, checkout, início de sessão, registo e área de cliente, com as variáveis de ambiente já preenchidas com os seus URL e segredos.
A arquitetura é propositadamente simples: o seu WooCommerce continua a ser a fonte de verdade (produtos, encomendas, stocks, pagamentos) e o Next.js consome a API REST através de rotas proxy seguras. Sem duplicação de base de dados e sem replicação para gerir.
Requisitos
Do lado do WordPress
- WordPress 6.4 ou superior
- WooCommerce 8.0 ou superior (testado até à 9.5)
- PHP 8.1 ou superior
- Permalinks configurados em Nome do artigo (e não em Simples)
- HTTPS ativo (indispensável para os cookies httpOnly e para a autenticação em produção)
- Um par de chaves REST do WooCommerce em leitura e escrita (geradas em WooCommerce → Definições → Avançado → API REST)
Do lado do frontend Next.js
- Node.js 20 ou superior (recomendado: gerir as versões com o
nvm) - Alojamento compatível com Node: Vercel, VPS Hetzner, Netlify, Railway ou qualquer servidor capaz de executar Node 20+
Um alojamento partilhado clássico não serve para alojar o frontend Next.js, que exige um runtime Node persistente. O plugin WordPress, esse, funciona em qualquer alojamento WP.
Instalação do plugin WordPress
- No back-office do WordPress, vá a Plugins → Adicionar plugin → Carregar plugin.
- Selecione o ficheiro
dfheadlessstarterkit.zipe clique em Instalar agora. - Clique em Ativar plugin.
- Aparece um novo menu Headless Kit na barra lateral esquerda, com três separadores: Definições, Diagnósticos e Descarregar o starter.
Na ativação, o plugin gera automaticamente um segredo JWT e um token de revalidação aleatórios. Pode regerá-los a qualquer momento a partir das definições.
Configuração
Abra Headless Kit → Definições. Cada secção é independente e pode ser ajustada sem reiniciar seja o que for.
URL do frontend
Indique o URL público completo da sua aplicação Next.js, sem barra final. Exemplo:
https://loja.exemplo.pt
Este URL serve para três coisas: construir os webhooks ISR, alimentar a variável NEXT_PUBLIC_SITE_URL do starter entregue, e validar a origem CORS predefinida.
Segredo JWT e token de revalidação
São usados dois segredos:
- Segredo JWT: assina os tokens de acesso e de refresh. No mínimo 32 carateres. Nunca o partilhe.
- Token de revalidação: enviado no cabeçalho
Authorization: Bearer …dos webhooks ISR. Tem de ser igual à variávelREVALIDATE_TOKENdo lado do Next.js.
Um botão Regerar ao lado de cada campo produz um segredo aleatório criptograficamente sólido através do crypto.getRandomValues.
Depois de regerar o segredo JWT, todos os tokens de acesso e de refresh existentes ficam inválidos. Os utilizadores terão de iniciar sessão de novo. Avise-os ou faça-o fora das horas de maior tráfego.
Modo de carrinho: JWT ou servidor?
A escolha faz-se através de um botão de opção nas definições.
Modo JWT (predefinido, recomendado)
O carrinho completo é serializado num token assinado HS256 e devolvido através do cabeçalho X-DFHSK-Cart. Nenhum dado é guardado do lado do WordPress. Ideal para:
- Implantações em Vercel edge, Cloudflare ou em várias instâncias
- Lojas de tráfego elevado onde evitar a base de dados a cada chamada é um ganho claro
- Configurações em que o WordPress é puramente API e não precisa de sessões
Modo servidor (WC_Session)
O carrinho vive na tabela nativa WC_Session do WooCommerce. A privilegiar se:
- Usa extensões WooCommerce que fazem hook no carrinho (WooCommerce Subscriptions, Dynamic Pricing, plugins YITH, etc.)
- Quer conservar a lógica de sessão nativa do WooCommerce (recuperação nativa de carrinhos abandonados, cross-sell no servidor, etc.)
Origens CORS
Uma lista de permissões estrita das origens autorizadas a chamar a API. Uma origem por linha, no formato completo https://…. Os wildcards de subdomínio são suportados:
https://loja.exemplo.pt
https://preview.exemplo.pt
https://*.previews.exemplo.pt
http://localhost:3000
Acrescente http://localhost:3000 durante o desenvolvimento e retire-o em produção.
Eventos ISR
Cinco caixas de seleção indicam que eventos do WordPress desencadeiam um webhook ISR para o Next.js:
- Produtos:
save_post_product,woocommerce_update_product - Categorias: criação, atualização e eliminação de termos da taxonomia
product_cat - Encomendas: mudanças de estado (útil para atualizar a página da conta do cliente)
- Páginas:
save_post_page - Cupões: criação e atualização de códigos promocionais
Uma caixa de texto Caminhos a revalidar permite definir com precisão que caminhos do Next.js são revalidados em cada evento (por predefinição, o plugin deduz de forma inteligente os caminhos em causa).
Diagnósticos
Separador Headless Kit → Diagnósticos. São executadas onze verificações automáticas a cada apresentação da página:
- WooCommerce ativo: a classe
WooCommerceestá disponível - Permalinks limpos: a estrutura não é Simples
- API REST acessível: o
/wp-json/responde com 200 - HTTPS ativo: o
is_ssl()devolve true - WPGraphQL detetado: apenas informativo, não bloqueante
- Segredo JWT definido: no mínimo 32 carateres
- URL do frontend configurado: não vazio e com formato de URL válido
- Origens CORS preenchidas: pelo menos uma origem
- Token de revalidação definido: no mínimo 24 carateres
- Chaves REST do WooCommerce: o plugin deteta um par consumer_key/consumer_secret ativo
- Modo de carrinho legível: o armazenamento escolhido funciona
Cada verificação aparece a verde (OK), laranja (aviso, não bloqueante) ou vermelho (bloqueante). Resolva tudo o que estiver a vermelho antes de passar a produção.
Descarregar e lançar o starter Next.js
Depois de preencher as definições e com os diagnósticos a verde, abra Headless Kit → Descarregar o starter. Clique no botão grande Descarregar o starter Next.js.
O ZIP entregue é um projeto Next.js 15 completo, gerado na hora com os seus URL e segredos já injetados. Os marcadores substituídos na geração:
{{SITE_URL}}→ URL do seu WordPress{{FRONTEND_URL}}→ URL do front configurado{{REVALIDATE_TOKEN}}→ o seu token de revalidação{{CURRENCY}}→ moeda do WooCommerce{{SITE_NAME}}→ título do site{{LOCALE}}→ locale do WordPress (pt, fr, en, es, etc.)
O ficheiro .envtmpl passa a chamar-se .env.example na geração.
Variáveis de ambiente a completar manualmente
Alguns valores não podem ser obtidos automaticamente e têm de ser acrescentados ao ficheiro .env (a criar a partir do .env.example):
WOO_REST_CONSUMER_KEY=ck_xxxxxxxxxxxxxx
WOO_REST_CONSUMER_SECRET=cs_xxxxxxxxxxxxxx
SESSION_PASSWORD=a-sua-palavra-passe-de-32-carateres-no-minimo
Gere uma SESSION_PASSWORD sólida:
node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"
Desenvolvimento local
npm install
cp .env.example .env
# Edite o .env com os segredos em falta
npm run dev
O front fica acessível em http://localhost:3000. Acrescente este URL às origens CORS do lado do WordPress durante o desenvolvimento.
Implantação em Vercel
npx vercel link
npx vercel env pull .env.production
npx vercel deploy --prod
Configure depois todas as variáveis de ambiente no dashboard da Vercel (Project → Settings → Environment Variables). O ficheiro vercel.json entregue fixa a região em cdg1 (Paris) e desativa a cache nas rotas /api/*.
Implantação em Hetzner (ou em qualquer VPS Ubuntu/Debian)
# No servidor, como root ou com sudo
git clone o-seu-repo.git storefront && cd storefront
cp .env.example .env
nano .env # Preencha todas as variáveis
bash deploy/hetzner.sh
O script instala o Docker se for necessário, constrói a imagem, lança o contentor e expõe o serviço em 127.0.0.1:3000. Acrescente o Caddy ou o nginx como reverse-proxy para o TLS. Exemplo de Caddyfile mínimo:
loja.exemplo.pt {
encode zstd gzip
reverse_proxy 127.0.0.1:3000
}
Endpoints REST expostos
Todos os endpoints do plugin estão no namespace dfhsk/v1. URL completo: https://exemplo.pt/wp-json/dfhsk/v1/…
Autenticação
POST /auth/login: corpo{ username, password }→ devolve{ token, refresh_token, user }POST /auth/refresh: corpo{ refresh_token }→ devolve um novotokenGET /auth/me: cabeçalhoAuthorization: Bearer …→ devolve o utilizador atualPOST /auth/register: corpo{ email, password, first_name, last_name }POST /auth/logout: invalida o refresh token
Carrinho
Todas as chamadas transmitem o token de carrinho através do cabeçalho X-DFHSK-Cart. O servidor devolve um novo token no mesmo cabeçalho em cada resposta.
GET /cart: snapshot completo (itens, totais, impostos, portes)POST /cart/add: corpo{ product_id, quantity, variation? }POST /cart/update: corpo{ key, quantity }POST /cart/remove: corpo{ key }POST /cart/coupon: corpo{ code }DELETE /cart/coupon/{code}POST /cart/shipping: corpo{ country, postcode }→ devolve as tarifas aplicáveisPOST /cart/clear
Checkout
POST /checkout/create-order: corpo{ payment_method, billing, shipping? }→ devolve{ order_id, order_key, redirect }. Oredirecté o URL para o gateway de pagamento (Stripe, PayPal, etc.).GET /checkout/order/{id}: exige o cabeçalhoAuthorization: Bearer …
Configuração pública
GET /config: acessível sem autenticação. Devolve{ currency, base_country, countries, payment_methods, tax_settings }. O starter Next.js usa este endpoint para preencher os formulários de checkout.
Webhooks ISR (do lado do Next.js)
O plugin envia pedidos POST para {FRONTEND_URL}/api/revalidate com o cabeçalho Authorization: Bearer {REVALIDATE_TOKEN}. O corpo é um JSON:
{
"paths": ["/products/casaco-linho", "/products"],
"tags": ["product:casaco-linho"],
"reason": "wc_update_product"
}
A rota /api/revalidate entregue no starter valida o token e depois chama revalidatePath e revalidateTag para cada entrada.
Personalizar o starter
O código entregue está sob licença GPL v2: pode alterar, estender e redistribuir sem restrições. Os pontos de entrada habituais:
- Paleta de cores:
tailwind.config.ts, paletabrand(laranja por predefinição) - Componentes da loja:
src/components/shop/(Header, Footer, ProductCard, CartProvider) - Páginas públicas:
src/app/(shop)/ - Páginas da conta do cliente:
src/app/(auth)/ - Formato de preços e datas:
src/lib/format.ts - Tipos TypeScript:
src/types/woo.ts - Helper de chamada à API:
src/lib/woo-rest.ts(funçõeswooRestedfhskFetch)
Para acrescentar uma nova página que liste, por exemplo, os produtos de uma marca, duplique src/app/(shop)/products/page.tsx e adapte a query da REST do WooCommerce. A função wooRest<T>() trata automaticamente da autenticação Basic.
Resolução de problemas
Erro de CORS na consola do navegador
A origem do front não consta da lista de permissões. Acrescente-a em Definições → Origens CORS, uma por linha, sem barra final.
Webhooks ISR que respondem 401
O REVALIDATE_TOKEN do lado do Next.js não corresponde ao token configurado do lado do WordPress. Copie o valor exato das definições do WP para o .env do Next.js e volte a implantar.
O login devolve 403 apesar de as credenciais estarem corretas
Verifique que a conta de utilizador tem mesmo uma palavra-passe definida (e não apenas um início de sessão social), que o HTTPS está ativo em produção, e que o segredo JWT tem pelo menos 32 carateres. Consulte o separador Diagnósticos.
O carrinho esvazia-se entre duas páginas
No modo JWT, verifique que o starter lê e escreve mesmo o token no localStorage (chave dfhsk_cart_token). Abra o inspetor do navegador → separador Application → Local Storage.
Uma encomenda criada no WooCommerce não aparece do lado do Next.js
Verifique que o evento Encomendas está assinalado nos eventos ISR e que o webhook parte sem erro (ative o WP_DEBUG_LOG).
Ir mais longe
O starter é um ponto de partida, não um produto acabado. Consoante o seu projeto, considere acrescentar:
- Um motor de pesquisa instantânea (Algolia, Meilisearch, Typesense) alimentado pelos mesmos webhooks ISR
- Um CMS de conteúdo editorial do lado do WordPress com o plugin ACF ou equivalente, e uma página Next.js dedicada
- Uma PWA com service worker para o modo offline (ver também o nosso módulo dfpwa)
- Personalização por IA em tempo real (ver dfsmartcontent)
Para qualquer questão técnica, contacte o suporte DataFirefly com os seus registos e os resultados do separador Diagnósticos.