Preview Content Changes

This article will show you how to preview content changes without publishing your document or rebuilding your project.


Previews

One of the most powerful features of Prismic is Previews, which gives content editors the ability to preview content without publishing it to a live site. The Toolbar also allows you to edit your pages. On your website, click the edit button displayed on the bottom left page, select the part of the page that you want to edit, and you'll be redirected to the appropriate page in the Writing Room.


1. Configure Preview Mode in your Next App

You need to set the Next Preview mode configuration. If it doesn't already exist, create an API directory: ~/pages/api. Inside of this ~/pages/api directory, create two new files:

  1. preview.js
  2. exit-preview.js (Required file to exit a preview session correctly).

1.1. preview.js

The preview configuration uses the NextsJS setPreviewData method which sets some cookies on the browser, turns on the preview mode, and redirects the request to the appropriate URL. You need to add the following code in this file:

Copy
import { Client, linkResolver } from "../../prismic-configuration"

export default async (req, res) => {
  const { token: ref, documentId } = req.query;
  const redirectUrl = await Client(req)
    .getPreviewResolver(ref, documentId)
    .resolve(linkResolver, '/');

  if (!redirectUrl) {
    return res.status(401).json({ message: 'Invalid token' });
  }

  res.setPreviewData({ ref });

  res.write(
    `<!DOCTYPE html><html><head><meta http-equiv="Refresh" content="0; url=${redirectUrl}" />
    <script>window.location.href = '${redirectUrl}'</script>
    </head>`
  );
  res.end();
};

The Link Resolver Function

This requires the use of a Link Resolver function so that the preview endpoint knows where to redirect to. You can learn more about link resolving by checking out the Link Resolver documentation.

You either need to define the Link Resolver in the Preview component or import it.

1.2. exit-preview.js

Whenever you have an active preview session, and you want to exit you'll need to manually add /api/exit-preview to the URL in the browser. See the following examples:

Copy
export default async (_, res) => {
  res.clearPreviewData();

  res.writeHead(307, { Location: "/" });
  res.end();
};

1.3. 'Exit Next.js Preview' button

You can create an exit preview component button <ExitPreviewButton /> to hit the exit preview route you just created above, which you only show if the preview data is present. This button will clear the _next_preview_data cookie from your application.

Copy
import React from 'react'
import { useRouter } from 'next/router'
export default function Layout({ children }) {
  const { isPreview } = useRouter()
  return (
    <div>
      {children}
      {isPreview ? (
        <a href="/api/exit-preview">Exit Preview</a>
      ) : null}
    </div>
  )
}

You then include this component everywhere in your project using the layout.


2. Add the Toolbar /Edit Button Script

The toolbar does multiple things for you, it will add an edit button to your website to quickly jump to the correct document in Prismic. It will show you a preview of the JSON response with Dev Mode. It will update the preview content when a change occurs and will allow you to clear the Prismic preview cookie.

To add the toolbar script for your repository go to the _document.js file in the directory at ~/pages/_document.js. Here we will import the API Endpoint from wherever it's stored, extract the repo ID from this string using regular expressions and pass it to the toolbar script in the <head> component as a variable called prismicRepoName.

You can see the full code from the _document.js below:

Copy
import Document, { Html, Head, Main, NextScript } from "next/document";
import { createResolver } from "next-slicezone/resolver";

import { apiEndpoint } from "./../prismic-configuration"; // import the endpoint name from where it's defined
const prismicRepoName = /([a-zA-Z0-9-]+)?(\.cdn)?\.prismic\.io/.exec(apiEndpoint)[1] //Regex to get repo ID

export default class extends Document {
  static async getInitialProps(ctx) {
    const initialProps = await Document.getInitialProps(ctx);
    await createResolver();
    return { ...initialProps };
  }

  render() {
    return (
      <Html>
        <Head>
          <script async defer src={`//static.cdn.prismic.io/prismic.js?repo=${prismicRepoName}&new=true`} />
        </Head>
        <body>
          <Main />
          <NextScript />
        </body>
      </Html>
    );
  }
};

3. Enable Previews in your Repository

In order to enable preview, you need to add the preview configuration inside your repository. Here are the following steps:

  1. Go to your repository, navigate to Settings > Previews and add the configuration for a preview.
  2. Enter the preview Site Name, Domain, and Link Resolver route. Add the /api/preview route for the Link Resolver field.
  3. You can add as many preview URL's as you need. This allows you to have a production server, staging server, development server, etc. Discover how to handle multiple environments in Prismic.

4. Trigger a Preview in Prismic repository

To view a preview of your content changes, make a change, click 'Save' and click the 'eye' icon, this will either open the preview or ask you to pick one of your preview environments.

4.1. Share a Preview Link

When you click on the "Preview" button on your document page, a new tab will open a preview page. Once you're on a preview page, you can click on the bottom left button and copy the shareable link and share it with your team. Your team members don't need to have a Prismic account to see the previews.

5. Hot reloads in Next.js

Because of the unique way previews are handled in Next.js, you will need to add some extra code to have hot reloads for preview data in your Next.js application. That is to say, if a change is made and saved in Prismic your Next.js app will get the new data without the preview button needing to be clicked again.

Essentially what you need is to create a hook by making a file called useUpdatePreviewRef.js somewhere in your project which checks the Prismic Preview cookie against the _next_preview_data cookie and triggers a new preview if it’s not correct.

You can see the code for this hook below:

Copy
import { useEffect } from 'react'
import { useRouter } from 'next/router'
import Cookies from 'js-cookie'

import { apiEndpoint } from "./../prismic-configuration"; // import the endpoint name from where it's defined
const prismicRepoName = /([a-zA-Z0-9-]+)?(\.cdn)?\.prismic\.io/.exec(apiEndpoint)[1] //Regex to get repo ID

export default function useUpdatePreviewRef(preview, documentId) {
  const router = useRouter()
  useEffect(() => {
    if (router.isPreview) {
      const rawPreviewCookie = Cookies.get('io.prismic.preview')
      if (rawPreviewCookie) {
        const previewCookie = JSON.parse(rawPreviewCookie)
        const previewCookieObject = previewCookie[`prismicRepoName.prismic.io`]
        const previewCookieRef = previewCookieObject && previewCookieObject.preview
          ? previewCookieObject.preview
          : null
        if (previewCookieRef && preview.activeRef !== previewCookieRef) {
          return router.push(`/api/preview?token=${previewCookieRef}&documentId=${documentId}`)
        }
      } else {
        return router.push('/api/exit-preview')
      }
    }
    return undefined
  }, [])
}

You then import this hook into your pages, like a dynamic page [uid].js. Then pass the page function the preview data and the check happens here inside the getStaticProps query for your page:

Copy
import React from 'react'
import { Client } from "../prismic";
import useUpdatePreviewRef from 'tools/hooks/useUpdatePreviewRef' //import from where you store this file

export default function Page({ page, preview }) {
  useUpdatePreviewRef(preview, page.id)
  return (
    <p>Your page content</p>
  )
}

export async function getStaticProps({ params, previewData }) {
  const ref = previewData ? previewData.ref : null
  const client = Client();
  const PageContent = (await client.getByUID('page', params.uid)
  const { page } = PageContent
  return {
    props: {
      page: page || null,
      preview: {
        activeRef: ref,
      },
    },
  }
}

Now your app will automatically reload when the preview data is updated.


Related articles:


Was this article helpful?
Not really
Yes, Thanks

Can't find what you're looking for? Get in touch with us on our Community Forum.