Muchas redacciones y equipos de producto quieren seguir usando WordPress por su panel editorial, roles, plugins y flujos… pero desean un frontend más rápido, seguro y flexible. Ahí entra el enfoque headless: WordPress se queda como CMS, y Astro renderiza la web consumiendo tu contenido por REST o GraphQL. Resultado: la sala de redacción no cambia su rutina, y el sitio carga como un rayo con HTML estático o SSR ligero.
A continuación, un recetario pensado para un blog de noticias en WordPress que no quiere renunciar a su CMS y busca rendimiento, SEO y control en el front.
Arquitectura en una frase
- Back: WordPress (editor, revisiones, ACF/Gutenberg, plugins, taxonomías).
- API: WordPress REST API (
/wp-json/wp/v2/…) o WPGraphQL. - Front: Astro (SSG/SSR/ISR), componentes, rutas, optimización de imágenes, CDN.
- CI/CD: build/despliegue del front al publicar o actualizar contenido (webhooks).
1) Preparar WordPress como CMS (nada cambia para la redacción)
- Editor: Gutenberg o clásico, tal y como está.
- Plugins habituales: SEO, ACF, campos personalizados, taxonomías, etc.
- API:
- REST: viene activada por defecto. Endpoints típicos:
- Posts:
/wp-json/wp/v2/posts - Categorías:
/wp-json/wp/v2/categories - Medios:
/wp-json/wp/v2/media
- Posts:
- GraphQL: instala WPGraphQL (opcional) si prefieres consultas tipadas.
- REST: viene activada por defecto. Endpoints típicos:
- Seguridad/privacidad: por defecto la REST pública solo lee contenido publicado. Para contenido protegido o preview, usa auth (JWT, Application Passwords) o un endpoint /preview controlado.
Consejo: expón solo lo necesario usando REST _fields y WPGraphQL con allowlist de esquemas.
2) Crear el frontend en Astro
2.1. Empezar proyecto
npm create astro@latest
# elige template vacío o de blog según necesidad
Lenguaje del código: CSS (css)
2.2. Listado de noticias (REST)
---
// src/pages/index.astro
import Layout from "../layouts/Layout.astro";
// Solo los campos necesarios
const res = await fetch(
"https://TU-SITIO/wp-json/wp/v2/posts?_fields=id,slug,title,excerpt,link,date&_embed&per_page=10"
);
const posts = await res.json();
---
<Layout title="Últimas noticias">
<main>
<h1>Últimas noticias</h1>
{posts.map((post) => (
<article>
<h2>
<a href={`/noticias/${post.slug}/`} set:html={post.title.rendered} />
</h2>
<p set:html={post.excerpt.rendered} />
{/* Imagen destacada (si la hay) */}
{post._embedded?.['wp:featuredmedia']?.[0]?.media_details?.sizes?.medium?.source_url && (
<img
src={post._embedded['wp:featuredmedia'][0].media_details.sizes.medium.source_url}
alt={post._embedded['wp:featuredmedia'][0].alt_text || post.title.rendered}
loading="lazy"
/>
)}
</article>
))}
</main>
</Layout>
Lenguaje del código: JavaScript (javascript)
2.3. Página de noticia (ruta dinámica + SSG)
---
// src/pages/noticias/[slug].astro
import Layout from '../../layouts/Layout.astro';
export async function getStaticPaths() {
const data = await fetch("https://TU-SITIO/wp-json/wp/v2/posts?per_page=100&_fields=slug");
const posts = await data.json();
return posts.map((p) => ({ params: { slug: p.slug } }));
}
const { slug } = Astro.params;
const res = await fetch(`https://TU-SITIO/wp-json/wp/v2/posts?slug=${slug}&_embed`);
const [post] = await res.json();
---
<Layout title={post?.title?.rendered || "Noticia"}>
<article>
{post?._embedded?.['wp:featuredmedia']?.[0]?.source_url && (
<img src={post._embedded['wp:featuredmedia'][0].source_url} alt="" />
)}
<h1 set:html={post.title.rendered} />
<p><small>{new Date(post.date).toLocaleDateString()}</small></p>
<Fragment set:html={post.content.rendered} />
</article>
</Layout>
Lenguaje del código: JavaScript (javascript)
Variantes:
- SSR en vez de SSG si quieres páginas siempre frescas.
- ISR (Incremental Static Regeneration): revalidar estáticos tras X minutos/horas.
3) Paginación, categorías y archivos
- Paginación REST: usa
?page=N&per_page=Ky el headerX-WP-TotalPages. - Categorías: lista
/wp-json/wp/v2/categories, filtra posts con?categories=ID. - Etiquetas: igual que categorías con
/wp-json/wp/v2/tags. - Archivo por fecha: filtra por
after/before(o monta colección en Astro tras traer los posts).
4) Compatibilidad con ACF y campos personalizados
- REST: expón campos personalizados con plugins (por ejemplo, ACF to REST API), o añade endpoints propios.
- GraphQL: WPGraphQL + WPGraphQL for ACF facilita consultar campos tipados.
Ejemplo WPGraphQL (posts + campos):
query LatestPosts {
posts(first: 10) {
nodes {
slug
title
excerpt
featuredImage { node { sourceUrl } }
date
acf_campos {
autorInvitado
lecturaMinutos
}
}
}
}
5) Preview editorial y contenido protegido
- Preview: implementa una ruta
src/pages/api/preview.tsque valide un token, consulte WP (draft) y redirija a la URL de la noticia en Astro con SSR. - Contenido members-only: sirve la vista pública desde Astro y carga el bloque restringido vía API con auth (JWT) tras validar sesión.
6) Webhooks, builds y frescura del contenido
- SSG + Webhooks: al publicar/actualizar en WP, dispara un hook (Netlify/Vercel/GitHub Actions) para reconstruir el front.
- SSR/ISR: si necesitas latas “siempre al día”, combina caché en CDN con revalidación.
- Estrategia mixta: portada/canales en SSR/ISR y fichas de noticia en SSG.
7) SEO, rendimiento e imágenes
- SEO:
- Componente
<Head>con title, meta description, OpenGraph/Twitter y JSON-LD (artículo). @astrojs/sitemapyrobots.txt.- Conserva slugs y plan de redirects si cambian URLs.
- Componente
- Rendimiento:
- Astro genera HTML estático por defecto (cero JS si no lo necesitas).
@astrojs/imagepara resize/AVIF/WebP, lazy y responsive.- CDN para caché de HTML y assets; comprueba TTFB/LCP/CLS.
- Imágenes de WP: con
_embedrecuperas tamaños; también puedes proxificar o descargar medios a tu pipeline si necesitas control total.
8) Seguridad
- WordPress: mantén actualizado, limita acceso al login, WAF, 2FA, copias de seguridad.
- API: limita a lo necesario con
_fields, activa CORS solo para tu dominio, rate limiting. - Front: cabeceras CSP, HSTS, X-Frame-Options, auditorías periódicas.
9) Despliegue y dominio
- Front (Astro): Vercel, Netlify, Cloudflare Pages, Render, fly.io o tu VPS.
- Dominio principal → Astro.
- WordPress en subdominio (p. ej.
cms.midominio.com) o detrás de VPN/Basic Auth si no debe ser público. - CI/CD: GitHub Actions/GitLab CI (build + deploy). Recomendado: revisiones previas con previews en cada PR.
10) Checklist express
- Inventario de endpoints: posts, categorías, medios, campos personalizados.
- Elegir REST/GraphQL y exponer solo lo necesario.
- Proyecto Astro (SSG/SSR/ISR) y rutas: portada, detalle, archivo, categoría.
- Paginación y _embed para imágenes destacadas.
- SEO (Head, OG, JSON-LD), sitemap y robots.
- Webhooks/build o revalidación para frescura.
- Caché y CDN (HTML + assets).
- Seguridad (CORS, rate limit, CSP) y observabilidad (logs/metrics).
- Previews editoriales y, si aplica, auth para contenido privado.
- Plan de redirects si cambia alguna URL.
Preguntas frecuentes
¿Seguiremos editando igual en WordPress?
Sí. El equipo editorial no cambia su flujo. WordPress sigue siendo el CMS; Astro solo lee la API y renderiza el front.
¿REST o GraphQL?
REST es cero fricción y suficiente para la mayoría. GraphQL (con WPGraphQL) te da tipado y control fino de selección. Si usas muchos ACF complejos, GraphQL suele ser cómodo.
¿Cómo se actualiza el front cuando publicamos una noticia?
Con webhooks que disparan el build/deploy del front (SSG), o usando SSR/ISR para evitar reconstrucciones completas.
¿Qué pasa con mis plugins (ACF, SEO, etc.)?
Siguen en WordPress. Si afectan al contenido (campos, HTML), exponlos por REST/GraphQL. El front (Astro) se encarga de presentarlo con mejor rendimiento y control.
¿Se pierde SEO al pasar a headless?
No. Al contrario: Astro entrega HTML rápido y optimizado. Mantén slugs, implementa sitemap/robots, metas correctas y datos estructurados.
Conclusión
El modelo WordPress headless con Astro te permite conservar todo lo que hace fuerte a WordPress (editorial, plugins, flujo de trabajo) y ganar un frontend moderno con Core Web Vitals sobresalientes, seguridad y portabilidad. Es una transición sensible para un medio de noticias: el equipo sigue publicando donde siempre, y el lector lo nota donde importa—en la velocidad y la experiencia.