Creating a Headless WordPress Site with Strapi: A Step-by-Step Guide

Table of Contents
Big thanks to our contributors those make our blogs possible.

Our growing community of contributors bring their unique insights from around the world to power our blog. 

If you love WordPress’s publishing workflow but crave the flexibility of a modern headless CMS architecture, pairing WordPress content with a Strapi front-end can give you the best of both worlds. In this guide, you’ll learn how to:

  1. Expose your existing WordPress posts via the WP REST API
  2. Spin up a Strapi instance and source WP content as “remote” data
  3. Define Strapi content types that mirror your WordPress schema
  4. Synchronize and enrich posts in Strapi
  5. Build a decoupled front-end (e.g. Next.js) consuming Strapi’s API

By the end, you’ll have a headless setup where WordPress remains your editor, Strapi becomes your unified API layer, and your front-end can fetch structured content with ease.

1. Why Combine WordPress with Strapi?

  • Familiar Editor: Keep WordPress’s Gutenberg experience for authors.
  • Unified API Layer: Strapi aggregates WP data, lets you add custom fields, relationships, and plugins.
  • Modern Front-end: Consume a single JSON API (Strapi) in React, Vue, or any framework.
  • Extensibility: Add non-WP data (e.g., products, events) into Strapi alongside posts.

2. Prerequisites

  • A WordPress site (v5+) with administrator access
  • Node.js (14+) and npm or Yarn installed
  • Basic familiarity with Strapi and headless CMS concepts
  • (Optional) A front-end framework like Next.js

3. Expose WordPress Content via the REST API

WordPress ships with the REST API enabled by default, but you may want to:

  1. Install JWT Authentication Plugin (if you need protected routes)
  2. Whitelist Custom Fields: Use WP REST API Controller to expose ACF fields.
  3. Test the Endpoint: bashCopyEditcurl https://your-wp-site.com/wp-json/wp/v2/posts You should see an array of posts in JSON, including title.rendered, content.rendered, date, and any custom fields.

4. Spin Up a Strapi Project

In a new directory:

bashCopyEditnpx create-strapi-app@latest headless-wp-strapi --quickstart
cd headless-wp-strapi

This creates a Strapi server running at http://localhost:1337, with an auto-generated admin user you configure on first load.

5. Define Content Types in Strapi

In Strapi’s Admin UI, under Content-Type Builder:

  1. Create a Collection Type named Post with fields:
    • title (Text)
    • slug (UID, based on title)
    • content (Rich Text)
    • publishedAt (DateTime)
    • Any custom fields you exposed (e.g., excerpt, featuredImage as Media).
  2. Save and Restart Strapi to update the API.

You now have REST endpoints at /posts, e.g. GET /posts, POST /posts.

6. Source WordPress Data into Strapi

6.1. Install the WP Source Plugin for Strapi

bashCopyEditnpm install strapi-plugin-remote

(Note: If no maintained plugin exists, you can write a lifecycle script to fetch WP posts.)

6.2. Configure the Remote Source

In config/plugins.js:

jsCopyEditmodule.exports = {
  'remote': {
    enabled: true,
    config: {
      sources: [
        {
          name: 'wordpress',
          url: 'https://your-wp-site.com/wp-json/wp/v2/posts',
          mapping: {
            posts: {
              contentType: 'api::post.post',
              fields: {
                title: 'title.rendered',
                slug: data => data.slug,
                content: 'content.rendered',
                publishedAt: 'date',
                excerpt: 'excerpt.rendered',
                featuredImage: 'yoast_head_json.og_image[0].url'
              },
            },
          },
        },
      ],
    },
  },
};

This tells Strapi to fetch WP posts and map fields into your Post type.

6.3. Run the Sync

Restart Strapi; the plugin will fetch and create entries in /posts. You can schedule this sync via cron or call it on-demand.

7. Enrich and Extend in Strapi

Now that posts live in Strapi:

  • Add Relations: Link Post to other types—e.g., Author, Category.
  • Add Permissions: Under Settings → Roles & Permissions, enable public find and findOne on posts.
  • Customize Controllers or Services: Add custom business logic—for example, filtering out drafts or enriching content.

8. Build Your Decoupled Front-end

Using Next.js as an example:

  1. Install Apollo or REST Client bashCopyEditnpm install axios
  2. Fetch Data in getStaticProps jsCopyEdit// pages/index.js import axios from 'axios'; export async function getStaticProps() { const { data: posts } = await axios.get('http://localhost:1337/api/posts'); return { props: { posts } }; } export default function Home({ posts }) { return ( <ul> {posts.map(p => ( <li key={p.id}> <a href={`/posts/${p.slug}`}>{p.title}</a> </li> ))} </ul> ); }
  3. Generate Dynamic Routes in pages/posts/[slug].js using getStaticPaths + getStaticProps.

9. Deploying Your Headless Setup

  • WordPress: Continue hosting on your existing LAMP/LEMP stack or WP-optimized host.
  • Strapi: Deploy to Heroku, DigitalOcean App Platform, or Strapi Cloud.
  • Front-end: Host on Vercel, Netlify, or any static-hosting service.

Ensure your front-end’s build servers can reach both WP and Strapi APIs, or use environment variables for endpoints.

Conclusion

By exposing WordPress content via its REST API and importing it into Strapi, you create a powerful headless architecture: authors keep using Gutenberg, developers gain a unified, extensible API in Strapi, and front-ends built in React, Vue, or other frameworks can fetch content statically or dynamically. This pattern lays a robust foundation for scaling content, integrating new data sources, and delivering high-performance user experiences.

Let's connect on TikTok

Join our newsletter to stay updated

Sydney Based Software Solutions Professional who is crafting exceptional systems and applications to solve a diverse range of problems for the past 10 years.

Share the Post

Related Posts