Tutorials / WordPress

Headless WordPress Setup with Astro and React - Complete Guide

Mahesh Mahesh Waghmare
3 min read Advanced

Headless WordPress separates content management from presentation, allowing you to use modern frontend frameworks like Astro and React while leveraging WordPress’s powerful CMS capabilities.

Introduction to Headless WordPress

Headless WordPress uses WordPress as a content API (head) while the frontend (body) is built with modern frameworks.

Benefits:

  • Modern frontend frameworks
  • Better performance
  • Enhanced security
  • Flexible deployment
  • Improved developer experience

Architecture:

  • WordPress backend (content management)
  • REST API or GraphQL (data layer)
  • Frontend framework (presentation)

WordPress Backend Setup

Enable REST API

WordPress REST API is enabled by default. Verify:

add_action('rest_api_init', function() {
    // Custom endpoints can be added here
});

CORS Configuration

Allow frontend to access 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, OPTIONS');
        header('Access-Control-Allow-Credentials: true');
        return $value;
    });
}, 15);

Custom Post Types

Register custom post types with REST API support:

register_post_type('project', [
    'public' => true,
    'show_in_rest' => true,
    'rest_base' => 'projects',
    'supports' => ['title', 'editor', 'thumbnail'],
]);
Advertisement

API Configuration

REST API Endpoints

Fetch Posts:

GET /wp-json/wp/v2/posts

Fetch Single Post:

GET /wp-json/wp/v2/posts/{id}

Fetch Pages:

GET /wp-json/wp/v2/pages

Custom Endpoints

add_action('rest_api_init', function() {
    register_rest_route('my-plugin/v1', '/custom-data', [
        'methods' => 'GET',
        'callback' => 'get_custom_data',
        'permission_callback' => '__return_true',
    ]);
});

function get_custom_data($request) {
    return new WP_REST_Response([
        'data' => 'value',
    ], 200);
}

Astro Frontend Integration

Install Dependencies

npm install axios

Create API Client

src/lib/wordpress-api.ts:

import axios from 'axios';

const API_URL = 'https://your-wordpress-site.com/wp-json/wp/v2';

export async function getPosts() {
    const response = await axios.get(`${API_URL}/posts`);
    return response.data;
}

export async function getPost(slug: string) {
    const response = await axios.get(`${API_URL}/posts?slug=${slug}`);
    return response.data[0];
}

export async function getPages() {
    const response = await axios.get(`${API_URL}/pages`);
    return response.data;
}

Fetch in Astro Pages

src/pages/blog/[…slug].astro:

---
import { getPost } from '../../lib/wordpress-api';

const { slug } = Astro.params;
const post = await getPost(slug);
---

<article>
    <h1>{post.title.rendered}</h1>
    <div set:html={post.content.rendered} />
</article>

React Components for WordPress

WordPress Post Component

import { useEffect, useState } from 'react';

export default function WordPressPost({ slug }: { slug: string }) {
    const [post, setPost] = useState(null);
    
    useEffect(() => {
        fetch(`https://your-site.com/wp-json/wp/v2/posts?slug=${slug}`)
            .then(res => res.json())
            .then(data => setPost(data[0]));
    }, [slug]);
    
    if (!post) return <div>Loading...</div>;
    
    return (
        <article>
            <h1 dangerouslySetInnerHTML={{ __html: post.title.rendered }} />
            <div dangerouslySetInnerHTML={{ __html: post.content.rendered }} />
        </article>
    );
}
Advertisement

Authentication and Security

Application Passwords

WordPress 5.6+ supports application passwords:

  1. Users → Profile → Application Passwords
  2. Create new password
  3. Use in Authorization header

API Authentication

const response = await fetch(`${API_URL}/posts`, {
    headers: {
        'Authorization': `Basic ${btoa('username:password')}`,
    },
});

Rate Limiting

Implement rate limiting on WordPress side to protect API.

Deployment Strategy

Separate Deployments

  • WordPress backend: Traditional hosting
  • Astro frontend: Static site hosting (Cloudflare Pages, Vercel, Netlify)

Build Process

{
  "scripts": {
    "build": "astro build",
    "preview": "astro preview"
  }
}

Environment Variables

PUBLIC_WP_API_URL=https://your-wordpress-site.com/wp-json/wp/v2

Conclusion

Headless WordPress setup provides:

  • Modern frontend development
  • Better performance
  • Flexible architecture
  • Enhanced security

Key steps:

  1. Configure WordPress REST API
  2. Set up CORS
  3. Create API client in Astro
  4. Build frontend components
  5. Deploy separately

This architecture gives you the best of both worlds: WordPress’s powerful CMS and modern frontend frameworks.

Advertisement
Mahesh Waghmare

Written by Mahesh Waghmare

I bridge the gap between WordPress architecture and modern React frontends. Currently building tools for the AI era.

Follow on Twitter