Skip To Main Content

Setting Up Post and Page Previews

This how to guide will guide you through the steps for viewing your WordPress content on the headless frontend as drafts or even before publishing.

Set Your Headless Secret

Your headless secret is a value that authenticates requests to WordPress. This secret enables you to view content that doesn’t publish on your Next.js frontend.

Copy your Headless Secret

Find your Headless Secret in WP-Admin -> Settings -> Faust. Copy this value:

The Faust plugin admin interface with a red rectangle around the Secret Key field

Add Your Headless Secret to Your .env.local File

If you are using a version of Faust previous to 0.2.1, use FAUSTWP_SECRET_KEY instead of FAUST_SECRET_KEY.

Add the FAUST_SECRET_KEY key to your .env.local file with the headless secret as the value. Your .env.local file should already have a value for NEXT_PUBLIC_WORDPRESS_URL. The file should look something like this:

# .env.local
# Your WordPress site URL

# Plugin secret found in WordPress Settings->Faust
Code language: PHP (php)

Create Your faust.config.js File and Import It In _app.js

Like the next/getting-started Faust example, your faust.config.js file.

You’ll need to import it at the top of your _app.js file to ensure the config is set, and your Faust app initializes appropriately.

// pages/_app.js
import '../faust.config';
import React from 'react';
import { useRouter } from 'next/router';
import { FaustProvider } from '@faustwp/core';
import '../styles/global.scss';

export default function MyApp({ Component, pageProps }) {
  const router = useRouter();

  return (
    <FaustProvider pageProps={pageProps}>
      <Component {...pageProps} key={router.asPath} />
Code language: JavaScript (javascript)

Create the Faust API Router

Next, you will need to create the apiRouter. This sets up the Faust API endpoints needed to authenticate requests from WordPress. Create a page at pages/api/faust/[[...route]].js with the following:

// pages/api/faust/[[...route]].js
import '../../../faust.config';
import { apiRouter } from '@faustwp/core';

export default apiRouter;
Code language: JavaScript (javascript)

Create Your Preview Page

With your headless secret set and the authorizeHandler ready to handle requests, you can now create a Next.js page for previews. Create a file at pages/preview.js with the following:

// pages/preview.js
import { WordPressTemplate } from '@faustwp/core';

export default function Preview(props) {
  return <WordPressTemplate {...props} />;

Code language: JavaScript (javascript)

Let’s break down what is going on here:

We are using the WordPressTemplate component from @faustwp/core that will determine the correct page or post type to render based on the wp-templates hierarchy exports.

We don’t use the getWordPressProps here as opposed in some other wp-template pages as we want to perform post previews in the client using CSRs.

Now in the wp-template pages, Faust will propagate a special boolean property asPreview=true so your component needs to pass it on the Page query and variables.

Here is an example taken from the next/getting-started Faust example of what you should do in your template hierarchy components if you wish to render previews:

// wp-templates/single.js
export default function Component(props) {
  // Loading state for previews
  if (props.loading) {
    return <>Loading...</>;
  // Code to render Single Post template hierachy type
Component.query = gql`
  query GetPost(
    $databaseId: ID!,
    $asPreview: Boolean = false
  ) {
    post(id: $databaseId, idType: DATABASE_ID, asPreview: $asPreview) {
Component.variables = ({ databaseId }, ctx) => {
  return {
    asPreview: ctx?.asPreview,
Code language: JavaScript (javascript)

The variables property function accepts a context parameter ctx that includes the boolean value asPreview. This will be true when you are previewing a page or false otherwise. We can leverage this parameter by inserting it in the query for requesting post or page previews.

We also need to consider the case when the component is still loading due to the CSR request. In such cases, we can render an empty or loading component when the post preview data is still in-flight:

if (props.loading) {
    return <>Loading...</>;
}Code language: JavaScript (javascript)

If you don’t handle the loading state, you may find that the post/page data will be undefined.

Is the asPreview Property Necessary?

If you wish to disable post/page previews for a particular template hierarchy page, you can simply ignore the asPreview parameter.

NOTE: For Safari Users

Safari has an active bug whereSecurecookies can not be set on localhost, even when other browsers allow them. (Faust sets a Secure cookie for our auth implementation.). See WebKit bug report.

For Locahost, it is advised to set up https which will make previews work with Safari.

Start by logging into your WordPress Admin. For this example, we’ll create a new post.

So far, I’ve added a title and a simple line of text for the content. To view this post as a preview on your front end, click the Preview link (1). From there, click, Preview in new tab (2):

WordPress post page using the Gutenberg editor with a red arrow to the preview and preview in new tab dropdowns

Notice that the Publish button is also visible, meaning that you still need to publish the post. Therefore, you can now view the post on the frontend without being authenticated.

Clicking on Preview in new tab should take you to your post preview page with the current preview content:

Post preview on the frontend in Next.js