How to Set Up a Headless WordPress Site with Astro
Tags: headless, wordpress, astro, cms
Published: 2024-06-27 07:26:14

Here, I'm diving into the exciting world of headless WordPress and Astro. If you're looking to combine the content management power of WordPress with the blazing-fast performance of a static site generator, you're in for a treat. Let's get started!

## Introduction

So, what's all this fuss about headless WordPress and Astro? Well, imagine taking WordPress's fantastic content management capabilities and pairing them with a modern, lightning-fast front end. That's exactly what we're doing here!

Headless WordPress means we're using WordPress solely as a backend, handling all our content creation and management. Meanwhile, Astro steps in as our front-end superhero, delivering that content to users with incredible speed and flexibility.

Why bother with this setup? Simple: you get the best of both worlds. Content editors can stick with the familiar WordPress interface, while developers can build a blazing-fast, SEO-friendly frontend using modern tools and frameworks. It's a win-win!

Before we dive in, I've got a hot tip for you: check out [AstroWP - headless WordPress starter kit](https://astrowp.com). It's an awesome resource that can jumpstart your headless WordPress project with Astro. While we'll be building our site from scratch in this tutorial, AstroWP is definitely worth exploring if you want to hit the ground running on future projects.
## Prerequisites

Before we jump in, let's make sure you've got everything you need:

1. A WordPress installation (don't worry, we'll cover this)
2. Basic knowledge of JavaScript and React (we'll be using some React components)
3. Node.js and npm installed on your machine
4. Familiarity with the command line (nothing too scary, I promise!)

Got all that? Great! Let's dive in.

## Setting Up WordPress

First things first, let's get WordPress up and running:

1. If you haven't already, install WordPress on your favorite web host. There are tons of great guides out there if you need help with this step.

2. Once WordPress is installed, log into your admin panel and head to the Plugins section. You need to install a crucial plugin called WPGraphQL. This nifty tool exposes your WordPress data through a GraphQL API, which we'll use to fetch content for our Astro site.

3. Search for "WPGraphQL" in the plugin directory, install it, and activate it. Easy peasy!

4. Now, let's create some sample content. Add a few blog posts and pages so we have something to work with. Don't stress about making it perfect – we're just testing things out.

Alright, our WordPress setup is good to go. Time to switch gears and set up Astro!

## Setting Up Astro

Now for the fun part – let's get Astro up and running:

1. Open up your terminal and navigate to where you want your project to live.

2. Run the following command to create a new Astro project:
   ```
   npm create astro@latest
   ```

3. Follow the prompts to set up your project. When asked about the template, choose "Empty" for now.

4. Once the installation is complete, cd into your new project directory and run:

   ```
   npm install
   ```

This will install all of the needed dependencies.

   ```
   npm run dev
   ```

This starts the development server and gives you a local preview of your site.

5. Open up your browser and navigate to `http://localhost:4321`. You should see a blank Astro site. Not very exciting yet, but we're about to change that!

Take a moment to explore the project structure. You'll see a `src` folder with `pages` and `components` subdirectories. This is where we'll be spending most of our time.

## Connecting Astro to WordPress

Now that we have both WordPress and Astro set up, it's time to introduce them to each other:

1. First, we need to install a few dependencies. Run the following command:
   ```
   npm install @astrojs/react react react-dom
   ```

2. Next, let's configure Astro to use React components. Open up your `astro.config.mjs` file and add the React integration:

   ```javascript
   import { defineConfig } from 'astro/config';
   import react from "@astrojs/react";

   export default defineConfig({
     integrations: [react()]
   });
   ```

3. Now, we need to set up our environment variables. Create a new file in your project root called `.env` and add the following:

   ```
   WP_URL=https://your-wordpress-site.com/graphql
   ```

   Replace `https://your-wordpress-site.com` with your actual WordPress site URL.

Great job! We've now got the groundwork laid for our headless WordPress + Astro site. In the next section, we'll start fetching data from WordPress and displaying it in our Astro site. Exciting times ahead!

## Fetching Data from WordPress

Alright, now we're getting to the good stuff. Let's fetch some data from WordPress and display it in our Astro site:

1. First, let's create a new file in the `src/pages` directory called `index.astro`. This will be our homepage.

2. Open up `index.astro` and add the following code:

   ```astro
   ---
   const response = await fetch(import.meta.env.WP_URL, {
     method: 'POST',
     headers: { 'Content-Type': 'application/json' },
     body: JSON.stringify({
       query: `
         query HomePagePosts {
           posts(first: 5) {
             nodes {
               title
               excerpt
               slug
             }
           }
         }
       `
     })
   });

   const json = await response.json();
   const posts = json.data.posts.nodes;
   ---

   <html lang="en">
     <head>
       <meta charset="utf-8" />
       <meta name="viewport" content="width=device-width" />
       <title>My Headless WordPress Site</title>
     </head>
     <body>
       <h1>Welcome to My Blog</h1>
       <ul>
         {posts.map((post) => (
           <li>
             <h2>{post.title}</h2>
             <p set:html={post.excerpt}></p>
             <a href={`/posts/${post.slug}`}>Read more</a>
           </li>
         ))}
       </ul>
     </body>
   </html>
   ```

   This code does a few things:
   - It sends a GraphQL query to our WordPress site to fetch the latest 5 posts.
   - It then takes that data and renders it in a simple HTML structure.

3. Save the file and check out your Astro dev server. You should now see your WordPress posts displayed on the page!

Pretty cool, right? We're now pulling data from WordPress and displaying it in our Astro site. But we can do even better. In the next section, we'll set up dynamic routing to create individual pages for each of our blog posts.

## Creating Dynamic Routes

Now that we've got our posts showing up on the homepage, let's create individual pages for each post:

1. Create a new file in `src/pages` called `posts/[slug].astro`. The square brackets in the filename tell Astro that this is a dynamic route.

2. Open `[slug].astro` and add the following code:

   ```astro
   ---
   export async function getStaticPaths() {
     const response = await fetch(import.meta.env.WP_URL, {
       method: 'POST',
       headers: { 'Content-Type': 'application/json' },
       body: JSON.stringify({
         query: `
           query AllPosts {
             posts {
               nodes {
                 slug
               }
             }
           }
         `
       })
     });

     const json = await response.json();
     const posts = json.data.posts.nodes;

     return posts.map((post) => {
       return {
         params: { slug: post.slug },
         props: { slug: post.slug },
       };
     });
   }

   const { slug } = Astro.props;

   const response = await fetch(import.meta.env.WP_URL, {
     method: 'POST',
     headers: { 'Content-Type': 'application/json' },
     body: JSON.stringify({
       query: `
         query SinglePost($slug: ID!) {
           post(id: $slug, idType: SLUG) {
             title
             content
           }
         }
       `,
       variables: {
         slug: slug,
       }
     })
   });

   const json = await response.json();
   const post = json.data.post;
   ---

   <html lang="en">
     <head>
       <meta charset="utf-8" />
       <meta name="viewport" content="width=device-width" />
       <title>{post.title}</title>
     </head>
     <body>
       <h1>{post.title}</h1>
       <div set:html={post.content}></div>
       <a href="/">Back to Home</a>
     </body>
   </html>
   ```

   This code does a few important things:
   - The `getStaticPaths` function fetches all post slugs from WordPress and tells Astro to create a page for each one.
   - We then fetch the specific post data for each page and render it.

3. Now, if you click on the "Read more" links on your homepage, you should be taken to individual post pages!

Awesome work! We've now got a fully functional headless WordPress site built with Astro. Of course, there's always room for improvement. In the next sections, we'll look at styling our site and optimizing its performance.

## Styling Your Astro Site

Now that we've got our content displaying correctly, let's make it look a bit nicer:

1. Astro supports several styling options out of the box. For this tutorial, we'll use Astro's built-in CSS support.

2. Create a new file in `src/styles` called `global.css`.

3. Add some basic styles to `global.css`:

   ```css
   body {
     font-family: Arial, sans-serif;
     line-height: 1.6;
     color: #333;
     max-width: 800px;
     margin: 0 auto;
     padding: 20px;
   }

   h1, h2 {
     color: #2c3e50;
   }

   a {
     color: #3498db;
     text-decoration: none;
   }

   a:hover {
     text-decoration: underline;
   }
   ```

4. Now, let's import this CSS file in our pages. In both `index.astro` and `posts/[slug].astro`, add this line in the `<head>` section:

   ```astro
   <link rel="stylesheet" href="/styles/global.css" />
   ```

5. Refresh your browser, and you should see a much nicer-looking site!

Remember, this is just a starting point. Feel free to expand on these styles and make the site your own!

## Optimizing Performance

One of Astro's big selling points is its focus on performance. Let's take advantage of some of Astro's features to make our site even faster:

1. Astro uses partial hydration, which means it only sends JavaScript to the browser when it's needed. This is great for performance, but we haven't actually used any client-side JavaScript yet. If you need interactivity, you can use Astro's client directives like `client:load` or `client:idle` on your components.

2. For image optimization, Astro has a built-in Image component. Let's use it for our post thumbnails. First, install the sharp package:

   ```
   npm install sharp
   ```

3. Then, in your `index.astro` file, import the Image component and use it for your post thumbnails:

   ```astro
   ---
   import { Image } from 'astro:assets';
   // ... rest of your frontmatter code
   ---

   <!-- In your HTML -->
   <Image src={post.featuredImage.node.sourceUrl} width={300} height={200} alt={post.title} />
   ```

   Note: You'll need to modify your GraphQL query to fetch the featured image data.

4. Astro also automatically optimizes your CSS and HTML. It removes unused CSS and minifies your HTML in production builds.

## Deployment

We're in the home stretch! Let's get your site deployed:

1. First, build your site with:

   ```
   npm run build
   ```

2. This will create a `dist` folder with your production-ready site.

3. You can deploy this folder to any static hosting service. Netlify and Vercel are popular options that work great with Astro.

4. If you're using Netlify, you can simply drag and drop your `dist` folder onto their site to deploy.

5. For automated deployments, you can set up a GitHub repository for your project and connect it to your hosting service. Then, every time you push to your main branch, your site will automatically rebuild and deploy.

## Summary

And there you have it! We've successfully set up a headless WordPress site with Astro. We've covered everything from initial setup to deployment, touching on data fetching, routing, styling, and performance optimization along the way.

Remember, this is just the beginning. There's so much more you can do with this setup. You could add custom post types, implement search functionality, or even turn your site into a full-fledged e-commerce platform.

I hope this tutorial has been helpful and has sparked some ideas for your own projects. Happy coding!

## Troubleshooting Common Issues

Before we wrap up, let's quickly address some common issues you might run into:

1. CORS errors: If you're getting CORS errors when trying to fetch data from WordPress, you may need to install a CORS plugin in WordPress or configure your server to allow cross-origin requests.

2. GraphQL errors: Double-check your query syntax if you're getting GraphQL errors. The WPGraphQL plugin provides a GraphiQL interface in the WordPress admin panel where you can test your queries.

3. Astro build problems: If you're having issues building your Astro site, make sure all your dependencies are up to date. You can also try clearing your `.astro` cache folder.

Remember, the Astro and WordPress communities are very helpful. If you run into any issues you can't solve, don't hesitate to reach out for help!