Guía · TutorialAstro 7WordPress REST API~15 min lectura

Cómo montar WordPress headless
con Astro paso a paso.

Tutorial completo para conectar WordPress como CMS headless con Astro 7. REST API, fetch tipado, listado de posts, páginas de detalle, sitemap y deploy. El mismo stack que usa Cris Culebras (Daruma Producciones) en producción.

01. Prepara WordPress

WordPress lleva la REST API integrada desde la versión 4.7: no necesitas instalar ningún plugin extra para empezar. Antes de tocar Astro, comprueba que tu WordPress está listo para servir contenido como CMS headless.

Verifica que la REST API está activa

Abre en el navegador https://tu-wordpress.com/wp-json/wp/v2/posts. Si ves un JSON con tus posts, la API funciona. Si ves un error 404, ve a Ajustes → Enlaces permanentes y guarda los cambios: eso regenera las reglas de reescritura.

Configura CORS si es necesario

Si WordPress y Astro van a estar en dominios diferentes durante desarrollo (localhost:4321 → tu-wp.com), necesitas permitir CORS en WordPress. Añade esto en functions.php de tu tema hijo o en un plugin custom:

functions.php
add_action('rest_api_init', function() {
  remove_filter('rest_pre_serve_request',
    'rest_send_cors_headers');
  add_filter('rest_pre_serve_request', function($value) {
    header('Access-Control-Allow-Origin: *');
    header('Access-Control-Allow-Methods: GET');
    return $value;
  });
});
Ojo:Access-Control-Allow-Origin: * está bien para desarrollo. En producción, reemplaza el asterisco por el dominio de tu Astro: 'https://tu-dominio.com'.

02. Crea el proyecto Astro

Si ya tienes un proyecto Astro, salta al paso 3. Si empiezas desde cero, o si prefieres partir de una base ya configurada, puedes usar el Starter Kit de Culebra Labque ya tiene la integración lista.

terminal
# Proyecto nuevo desde cero
npm create astro@latest mi-proyecto
cd mi-proyecto
npm install

# O clonar el starter de Culebra Lab (ya tiene todo configurado)
git clone https://github.com/DhiviPanda/astro-wp-starter
cd astro-wp-starter && npm install

Configura las variables de entorno

Crea un archivo .env en la raíz del proyecto con la URL de tu WordPress. Nunca subas este archivo a GitHub: añádelo a .gitignore.

.env
WP_API_URL=https://cms.tu-dominio.com/wp-json/wp/v2
WP_URL=https://cms.tu-dominio.com

03. Conecta la REST API

El patrón que usamos en todos los starters de Culebra Lab es centralizar todas las llamadas a la REST API de WordPress en un solo archivo de utilidades. Así si cambia la URL o la versión de la API, solo tocas un sitio.

src/lib/wordpress.ts
const WP_API = import.meta.env.WP_API_URL;

// Tipos básicos
export interface WPPost {
  id: number;
  slug: string;
  title: { rendered: string };
  excerpt: { rendered: string };
  content: { rendered: string };
  date: string;
  _embedded?: {
    'wp:featuredmedia'?: Array<{ source_url: string; alt_text: string }>;
  };
}

// Obtener todos los posts
export async function getPosts(perPage = 10): Promise<WPPost[]> {
  const res = await fetch(
    `${WP_API}/posts?per_page=${perPage}&_embed`
  );
  if (!res.ok) return [];
  return res.json();
}

// Obtener un post por slug
export async function getPost(slug: string): Promise<WPPost | null> {
  const res = await fetch(
    `${WP_API}/posts?slug=${slug}&_embed`
  );
  if (!res.ok) return null;
  const posts = await res.json();
  return posts[0] ?? null;
}

// Obtener slugs para rutas estáticas
export async function getPostSlugs(): Promise<string[]> {
  const posts = await getPosts(100);
  return posts.map(p => p.slug);
}

04. Listado de posts

Con las utilidades listas, crear la página de listado es sencillo. El fetch ocurre en el frontmatter de Astro: en build time, no en el navegador. El HTML resultante es completamente estático.

src/pages/blog/index.astro
---
import { getPosts } from '../../lib/wordpress';

const posts = await getPosts(12);
---

<ul>
  {posts.map(post => (
    <li>
      <a href={`/blog/${post.slug}/`}>
        <h2 set:html={post.title.rendered} />
        <p set:html={post.excerpt.rendered} />
      </a>
    </li>
  ))}
</ul>
Usa set:html en lugar de {post.title.rendered} para que Astro renderice correctamente las entidades HTML que WordPress incluye en los títulos (comillas tipográficas, ampersands, etc.).

05. Página de detalle

Para las páginas individuales necesitas rutas dinámicas. En Astro,getStaticPaths() se ejecuta en build time y genera una ruta estática por cada slug que devuelva WordPress.

src/pages/blog/[slug].astro
---
import { getPost, getPostSlugs } from '../../lib/wordpress';

export async function getStaticPaths() {
  const slugs = await getPostSlugs();
  return slugs.map(slug => ({ params: { slug } }));
}

const { slug } = Astro.params;
const post = await getPost(slug);
if (!post) return Astro.redirect('/404');

const featuredImage = post._embedded?.['wp:featuredmedia']?.[0];
---

<article>
  <h1 set:html={post.title.rendered} />
  {featuredImage && (
    <img
      src={featuredImage.source_url}
      alt={featuredImage.alt_text}
      width="1200" height="630"
    />
  )}
  <div set:html={post.content.rendered} />
</article>

06. Imágenes y rendimiento

Las imágenes de WordPress vienen como URLs externas en el JSON de la API. Astro no puede optimizarlas automáticamente como haría con imágenes locales, pero puedes mejorar el rendimiento con estas estrategias:

  • Pide el tamaño correcto desde la API: WordPress genera varios tamaños automáticamente. En lugar de pedir source_url, pide media_details.sizes.medium_large.source_url para el tamaño que necesitas.
  • Añade loading="lazy" en todas las imágenes que no sean above the fold.
  • Añade decoding="async" para evitar que el decode de imagen bloquee el hilo principal.
  • Añade siempre width y height: aunque no sean las dimensiones exactas, ayudan al navegador a reservar el espacio y evitan CLS.
  • Usa WebP si tu WordPress lo soporta: desde WP 5.8, WordPress genera automáticamente versiones WebP de las imágenes subidas.
Imagen optimizada desde la API de WordPress
const img = post._embedded?.['wp:featuredmedia']?.[0];
const src = img?.media_details?.sizes?.large?.source_url
  ?? img?.source_url;

// En el template:
<img
  src={src}
  alt={img?.alt_text ?? post.title.rendered}
  width="1200"
  height="630"
  loading="lazy"
  decoding="async"
/>

07. Sitemap y SEO

Con @astrojs/sitemap el sitemap se genera automáticamente en el build incluyendo todas las rutas estáticas, incluidas las generadas por getStaticPaths() desde WordPress.

terminal
npm install @astrojs/sitemap
astro.config.mjs
import { defineConfig } from 'astro/config';
import sitemap from '@astrojs/sitemap';

export default defineConfig({
  site: 'https://tu-dominio.com',
  integrations: [sitemap()],
});

Meta tags SEO en cada página

Para las páginas de detalle, usa los datos de WordPress para generar los meta tags de forma dinámica:

src/pages/blog/[slug].astro — head
const title = post.title.rendered.replace(/<[^>]+>/g, '');
const desc = post.excerpt.rendered.replace(/<[^>]+>/g, '').slice(0, 155);
const canonical = `https://tu-dominio.com/blog/${post.slug}/`;

// En el head:
<title>{title}</title>
<meta name="description" content={desc} />
<link rel="canonical" href={canonical} />
<meta property="og:title" content={title} />
<meta property="og:description" content={desc} />
<meta property="og:url" content={canonical} />

08. Deploy en producción

Astro genera un output estático en /dist: archivos HTML, CSS y JS listos para subir a cualquier hosting. No necesitas Node.js en producción.

terminal
# Build de producción
npm run build

# Preview local antes de subir
npm run preview

# Subir /dist a tu hosting por FTP
# (IONOS, SiteGround, cualquier hosting compartido)

Rebuildear cuando WordPress cambia

Como el output es estático, los cambios en WordPress no se reflejan automáticamente: necesitas rebuildar. Para automatizarlo, añade un webhook en WordPress que dispare el build cuando publiques contenido:

  • En Netlify o Vercel: copia la URL del build hook y añádela en WordPress → Ajustes → un plugin como WP Webhooks.
  • En hosting compartido (IONOS): programa un cron diario que ejecute el build y suba /dist por FTP.
  • Para sitios con poco volumen de publicación, el rebuild manual es perfectamente viable.
¿Quieres saltarte toda esta configuración y empezar desde una base ya probada? El Starter Kit de Culebra Labtiene todo esto preconfigurado: clónalo y conecta tu WordPress en 5 minutos.

Preguntas frecuentes

¿Necesito modificar el panel de WordPress para hacerlo headless?+

No. El panel de administración sigue funcionando exactamente igual. Los editores crean y publican contenido como siempre. El cambio ocurre solo en cómo se sirve ese contenido al visitante: en lugar de que WordPress genere el HTML, lo hace Astro.

¿Qué pasa con los plugins de Elementor o page builders?+

Dejan de ser necesarios para el frontend, porque el frontend ya no lo genera WordPress. Los plugins de backend (SEO, ACF, formularios) siguen funcionando con normalidad desde la REST API.

¿WordPress headless con Astro es mejor que Next.js?+

Depende del caso. Astro genera HTML estático por defecto: cero JS en el cliente, mejor rendimiento para sitios de contenido. Next.js tiene más ecosistema y SSR nativo. Para blogs, webs corporativas y landing pages, Astro gana en velocidad y simplicidad. Para aplicaciones con mucha interactividad, Next.js puede ser más adecuado.

¿Cuánto tarda en notarse la mejora de rendimiento tras la migración?+

El cambio en Lighthouse es inmediato tras el primer build. El impacto en posicionamiento suele notarse en las semanas siguientes, cuando Google rastrea de nuevo el sitio y registra las mejoras en Core Web Vitals.

¿Puedo desplegarlo en hosting compartido como IONOS?+

Sí. Astro genera un output estático en /dist. Sube ese directorio a tu public_html por FTP. El .htaccess incluido en los starters de Culebra Lab activa compresión y caché automáticamente.

¿Cuánto cuesta migrar WordPress a headless con Astro?+

Depende del proyecto. Cris Culebras (Daruma Producciones) hace la migración completa a WordPress headless + Astro desde 2.800€, con el contenido y las URLs migrados sin pérdidas. El starter kit de Culebra Lab es gratuito (licencia MIT) para quien quiera hacerlo por su cuenta.

Recursos relacionados

¿Lo migramos juntos?

Si prefieres que la migración la haga Cris Culebras, con sitemap, SEO técnico y optimización de imágenes incluidos, hablamos.