WordPress Headless con React y Next.js freelance Valencia: Guía completa desarrollo web 2025
WordPress Headless con React y Next.js freelance Valencia: Guía completa desarrollo web 2025
Introducción: WordPress no es solo blogs
Como desarrollador freelance, he visto cómo WordPress evoluciona constantemente. Lo que empezó como un CMS para blogs se ha convertido en una potente plataforma headless que alimenta millones de sitios modernos.
En este artículo te muestro cómo combinar WordPress como backend con React/Next.js como frontend para crear sitios ultrarrápidos, escalables y mantenibles.
Resultado: Sitios que cargan en <2 segundos, SEO perfecto y experiencia de desarrollo moderna.
¿Qué es WordPress Headless?
Arquitectura tradicional vs Headless
WordPress tradicional:
Usuario → WordPress (PHP) → Base de datos → Plantilla PHP → HTML
WordPress Headless:
Usuario → Next.js (React) → WordPress API → Base de datos → JSON
Ventajas del enfoque headless
✅ Rendimiento extremo: JavaScript moderno + optimizaciones automáticas
✅ Flexibilidad total: Cualquier framework frontend
✅ SEO optimizado: Server-side rendering + static generation
✅ Escalabilidad: CDN global + edge computing
✅ DX moderna: Hot reload, TypeScript, componentes reutilizables
Configuración del proyecto: Paso a paso
Paso 1: Configurar WordPress como headless CMS
Instalar WordPress
# Usar Local by Flywheel, XAMPP o servidor local
# Instalar WordPress 6.4+
Plugins esenciales para headless
// functions.php - Habilitar CORS y REST API
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, POST, PUT, DELETE, OPTIONS');
header('Access-Control-Allow-Headers: *');
return $value;
});
});
Plugins recomendados:
- WP REST API (incluido en WordPress 4.7+)
- WPGraphQL (para GraphQL en lugar de REST)
- Advanced Custom Fields PRO (campos personalizados)
- Yoast SEO (SEO automático)
- WP Rocket (cache y optimización)
Paso 2: Crear el proyecto Next.js
npx create-next-app@latest mi-sitio-headless --typescript --tailwind --app
cd mi-sitio-headless
npm install @apollo/client graphql # Para GraphQL
# o
npm install swr # Para REST API
Paso 3: Conectar WordPress con Next.js
Opción A: Usando REST API (sencillo)
// lib/wordpress.ts
const WP_URL = process.env.WP_URL || 'http://localhost:8080';
export async function getPosts() {
const response = await fetch(`${WP_URL}/wp-json/wp/v2/posts`);
return response.json();
}
export async function getPost(slug: string) {
const response = await fetch(`${WP_URL}/wp-json/wp/v2/posts?slug=${slug}`);
const posts = await response.json();
return posts[0];
}
Opción B: Usando GraphQL (recomendado)
// lib/graphql.ts
import { ApolloClient, InMemoryCache, gql } from '@apollo/client';
const client = new ApolloClient({
uri: `${WP_URL}/graphql`,
cache: new InMemoryCache(),
});
export const GET_POSTS = gql`
query GetPosts {
posts {
nodes {
id
title
slug
excerpt
featuredImage {
node {
sourceUrl
}
}
author {
node {
name
}
}
}
}
}
`;
Estructura del proyecto: Arquitectura escalable
Organización de archivos
src/
├── components/
│ ├── layout/
│ │ ├── Header.tsx
│ │ ├── Footer.tsx
│ │ └── Navigation.tsx
│ ├── posts/
│ │ ├── PostCard.tsx
│ │ ├── PostList.tsx
│ │ └── PostDetail.tsx
│ └── ui/
│ ├── Button.tsx
│ └── Loading.tsx
├── lib/
│ ├── wordpress.ts
│ ├── graphql.ts
│ └── utils.ts
├── app/
│ ├── (pages)/
│ │ ├── blog/
│ │ │ ├── page.tsx
│ │ │ └── [slug]/
│ │ │ └── page.tsx
│ │ └── page.tsx
│ └── layout.tsx
└── styles/
└── globals.css
Componentes reutilizables
// components/posts/PostCard.tsx
interface PostCardProps {
post: {
title: string;
slug: string;
excerpt: string;
featuredImage?: {
sourceUrl: string;
};
author: {
name: string;
};
};
}
export function PostCard({ post }: PostCardProps) {
return (
<article className="bg-white rounded-lg shadow-md overflow-hidden hover:shadow-lg transition-shadow">
{post.featuredImage && (
<img
src={post.featuredImage.sourceUrl}
alt={post.title}
className="w-full h-48 object-cover"
/>
)}
<div className="p-6">
<h2 className="text-xl font-bold mb-2">
<Link href={`/blog/${post.slug}`}>
{post.title}
</Link>
</h2>
<p className="text-gray-600 mb-4" dangerouslySetInnerHTML={{ __html: post.excerpt }} />
<div className="flex justify-between items-center">
<span className="text-sm text-gray-500">Por {post.author.name}</span>
<Link
href={`/blog/${post.slug}`}
className="text-blue-600 hover:text-blue-800 font-medium"
>
Leer más →
</Link>
</div>
</div>
</article>
);
}
Rutas dinámicas y generación estática
Static Site Generation (SSG) para posts
// app/blog/page.tsx
import { getPosts } from '@/lib/wordpress';
import { PostCard } from '@/components/posts/PostCard';
export default async function BlogPage() {
const posts = await getPosts();
return (
<div className="container mx-auto px-4 py-8">
<h1 className="text-3xl font-bold mb-8">Blog</h1>
<div className="grid md:grid-cols-2 lg:grid-cols-3 gap-6">
{posts.map((post) => (
<PostCard key={post.id} post={post} />
))}
</div>
</div>
);
}
// Generar rutas estáticas en build time
export async function generateStaticParams() {
const posts = await getPosts();
return posts.map((post) => ({
slug: post.slug,
}));
}
Server-Side Rendering (SSR) para posts individuales
// app/blog/[slug]/page.tsx
import { getPost } from '@/lib/wordpress';
import { notFound } from 'next/navigation';
interface PageProps {
params: {
slug: string;
};
}
export default async function PostPage({ params }: PageProps) {
const post = await getPost(params.slug);
if (!post) {
notFound();
}
return (
<article className="container mx-auto px-4 py-8 max-w-3xl">
<header className="mb-8">
<h1 className="text-4xl font-bold mb-4">{post.title}</h1>
<div className="flex items-center text-gray-600">
<span>Por {post.author.name}</span>
<span className="mx-2">•</span>
<time>{new Date(post.date).toLocaleDateString('es-ES')}</time>
</div>
</header>
{post.featuredImage && (
<img
src={post.featuredImage.sourceUrl}
alt={post.title}
className="w-full h-64 object-cover rounded-lg mb-8"
/>
)}
<div
className="prose prose-lg max-w-none"
dangerouslySetInnerHTML={{ __html: post.content }}
/>
</article>
);
}
Optimizaciones de rendimiento críticas
1. Imágenes optimizadas
// components/ui/OptimizedImage.tsx
import Image from 'next/image';
interface OptimizedImageProps {
src: string;
alt: string;
width?: number;
height?: number;
className?: string;
}
export function OptimizedImage({
src,
alt,
width = 800,
height = 600,
className
}: OptimizedImageProps) {
return (
<Image
src={src}
alt={alt}
width={width}
height={height}
className={className}
placeholder="blur"
blurDataURL="data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQ..."
/>
);
}
2. Cache inteligente
// lib/cache.ts
export const revalidate = 3600; // 1 hora
export async function getCachedPosts() {
'use cache';
return fetch(`${WP_URL}/wp-json/wp/v2/posts`, {
next: { revalidate: 3600 }
}).then(res => res.json());
}
3. Loading states y skeleton screens
// components/ui/Skeleton.tsx
export function PostSkeleton() {
return (
<div className="bg-white rounded-lg shadow-md overflow-hidden animate-pulse">
<div className="h-48 bg-gray-300"></div>
<div className="p-6">
<div className="h-6 bg-gray-300 rounded mb-4"></div>
<div className="h-4 bg-gray-300 rounded mb-2"></div>
<div className="h-4 bg-gray-300 rounded mb-4 w-3/4"></div>
<div className="flex justify-between">
<div className="h-4 bg-gray-300 rounded w-20"></div>
<div className="h-4 bg-gray-300 rounded w-16"></div>
</div>
</div>
</div>
);
}
SEO y meta tags dinámicos
Meta tags automáticos
// app/blog/[slug]/page.tsx
import { Metadata } from 'next';
export async function generateMetadata({ params }: PageProps): Promise<Metadata> {
const post = await getPost(params.slug);
return {
title: post.title,
description: post.excerpt.replace(/<[^>]*>/g, '').substring(0, 160),
openGraph: {
title: post.title,
description: post.excerpt.replace(/<[^>]*>/g, '').substring(0, 160),
images: post.featuredImage ? [post.featuredImage.sourceUrl] : [],
},
};
}
Schema.org markup
// components/seo/SchemaMarkup.tsx
interface SchemaMarkupProps {
post: any;
}
export function SchemaMarkup({ post }: SchemaMarkupProps) {
const schema = {
"@context": "https://schema.org",
"@type": "BlogPosting",
"headline": post.title,
"description": post.excerpt,
"author": {
"@type": "Person",
"name": post.author.name
},
"datePublished": post.date,
"image": post.featuredImage?.sourceUrl,
};
return (
<script
type="application/ld+json"
dangerouslySetInnerHTML={{ __html: JSON.stringify(schema) }}
/>
);
}
Casos de uso reales
Caso 1: Blog corporativo de agencia de marketing
Cliente: Agencia de marketing digital
Desafío: Blog lento con WordPress tradicional (5+ segundos de carga)
Solución: WordPress headless + Next.js
Tecnologías:
- WordPress + Advanced Custom Fields
- Next.js 14 + App Router
- Tailwind CSS
- Vercel (hosting)
Resultados:
- ⏱️ Tiempo de carga: 1.2s (vs 5.8s anterior)
- 📈 Core Web Vitals: 100/100
- 📊 Tráfico SEO: +150% en 3 meses
- 👥 Conversión: +40% en leads
Caso 2: E-commerce de productos digitales
Cliente: Plataforma de cursos online
Desafío: Necesitaban catálogo dinámico + blog + landings
Solución: WooCommerce headless + Next.js
Stack:
- WooCommerce + WooCommerce REST API
- Next.js + Stripe
- Sanity (para contenido adicional)
- Railway (hosting)
Resultados:
- 💰 Revenue: +200% en 6 meses
- 🔄 Checkout conversion: 85% (vs 65% anterior)
- ⚡ Performance: 98/100 Lighthouse
- 🛠️ Mantenimiento: 80% menos tiempo
Migración de WordPress tradicional a headless
Checklist de migración
Fase 1: Planificación (1 semana)
- Auditoría del contenido actual
- Diseño de la nueva estructura
- Setup del nuevo proyecto Next.js
- Configuración de WordPress headless
Fase 2: Desarrollo (2-3 semanas)
- Crear componentes base
- Migrar páginas principales
- Implementar sistema de blog
- Configurar SEO y analytics
Fase 3: Testing y optimización (1 semana)
- Testing en múltiples dispositivos
- Optimización de rendimiento
- Migración de redirecciones 301
- Configuración de monitoring
Fase 4: Lanzamiento (1 semana)
- Deploy gradual
- Monitoreo post-lanzamiento
- Optimizaciones finales
Herramientas de migración
// scripts/migrate-posts.ts
import fs from 'fs';
import { getPosts } from '../lib/wordpress';
async function migratePosts() {
const posts = await getPosts();
// Crear archivos MDX para cada post
posts.forEach(post => {
const frontmatter = `---
title: "${post.title}"
description: "${post.excerpt.replace(/<[^>]*>/g, '').substring(0, 160)}"
pubDate: "${post.date}"
author: "${post.author.name}"
---`;
const content = `${frontmatter}\n\n${post.content}`;
fs.writeFileSync(`./content/posts/${post.slug}.md`, content);
});
}
migratePosts();
Preguntas frecuentes
¿WordPress headless es más caro?
Respuesta: Inicialmente sí, pero a largo plazo es más rentable:
- Desarrollo inicial: +20-30% más costoso
- Mantenimiento: -50% menos costos
- Performance: +200-300% mejor
- Escalabilidad: Ilimitada vs limitada
¿Qué pasa con los plugins de WordPress?
Respuesta: Depende del plugin:
- ✅ SEO plugins: Funcionan perfectamente (Yoast, RankMath)
- ✅ Security: Continúan protegiendo el backend
- ✅ Custom fields: ACF funciona con REST API
- ❌ Frontend plugins: No se usan (themes, page builders)
¿Necesito conocimientos avanzados de React?
Respuesta: No necesariamente. Next.js es beginner-friendly:
- App Router: Más simple que Pages Router
- TypeScript: Opcional pero recomendado
- Componentes: Reutilizables y mantenibles
¿Cómo manejo los usuarios y autenticación?
Respuesta: Dos opciones:
- WordPress maneja auth: Usar JWT tokens
- Frontend maneja auth: Supabase, Firebase, Auth0
Conclusión: El futuro del desarrollo web
WordPress headless representa lo mejor de ambos mundos: la facilidad de gestión de contenido de WordPress con el rendimiento y flexibilidad de los frameworks modernos.
Si tienes un sitio WordPress tradicional lento o necesitas más flexibilidad, considera seriamente la migración a headless.
¿Quieres migrar tu WordPress a headless? Contáctame y te ayudo a planificar el proceso completo.
Recursos relacionados
- Astro vs Next.js: ¿Cuál elegir para tu proyecto web en 2025?
- Herramientas de IA para desarrollo web: Stack completo 2025
- SEO para IA: La guía definitiva para desarrolladores freelance
Publicado el 15 de diciembre de 2025 por Adrián Pozo Esteban - Desarrollador Full Stack Freelance especializado en WordPress headless, React y Next.js para empresas y startups en Valencia, España

