I know, I know... I've written a lot about headless WordPress and Astro lately. Is it the best solution for every site? By no means! But, it is a great solution for content heavy, high traffic sites that can utilize content templates and don't require a whole lot of customizable views. You can design the templates in Astro and easily send the data from WordPress when building pages.

Even though the templates are standard and you can create an experience within WordPress' Gutenberg editor to mimic the frontend of the site, many times it's still preferred to be able to preview new content before it is ready to be published.

How do I get a preview of new posts from WordPress?

If you are using a Server Side Rendering (SSR) approach for your headless site, you might not be as concerned with this. You can easily publish updates and see them in the time it takes to generate that page. Not the most elegant solution, but works a little better than publishing and building the whole site (Static Site Generation), even with incremental builds.

Create a preview template in your project.

Under the "pages" folder, create a new folder for "previews" and a single, dynamic template for {id}.astro. At the top of the file, we'll want to declare that this template should be generated server-side rather than at build time.

---
export const prerender = false;
---

Create an application password in WordPress

To query preview data, especially for posts that are still in draft (yes! You can see draft posts in preview without having to publish them), create an application password for your user account within WordPress. This is done from your user settings page.

When you create the password, it will be shown once with the ability to copy the password. If you miss copying or lose that password, it's easy to just "revoke" and create a new one as needed.

Update your GraphQl query

We'll need to update our GraphQl query to utilize the application password we just created, authorizing our application to pull the preview data for the provided posts.

const { id } = Astro.params;
const authString = `johndoe:${import.meta.env.WP_APPLICATION_PASSWORD}`;
const encodedAuth = Buffer.from(authString).toString("base64");

const entry = await fetch(`https://yourwebsite.com/graphql`, {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    Authorization: `Basic ${encodedAuth}`,
  },
  body: JSON.stringify({
    query: `{
      contentNode(id: "${id}", idType: DATABASE_ID, asPreview: true) {
        ... on Post {
          contentType {
            node {
              name
            }
          }
          [postData]
        }
        ... on Page {
          [pageData]
        }
      }
    }`,
  }),
});

We store our application password in a .env file so we're not making that accessible from the frontend. We then encode the password with our username (username:password) and pass it in for authorization with our headers in our fetch request.

Finally, I like to modify the query to utilize a generic contentNode so I can query for any type of post type that might be passed by ID to the template.

Display your content based on it's type

With this template update, whenever you go to yourdomain.com/preview/{id}, your site will generate a preview of the post associated with that ID. When it matches, you can update the layout of the template based on the matched contentType name. The easiest way is to abstract out the post layout and pass in any variables needed to output the template.