{"id":5185,"date":"2021-03-02T03:36:14","date_gmt":"2021-03-02T09:36:14","guid":{"rendered":"https:\/\/devrel.wpengine.com\/previews-in-headless-wordpress-using-nextjs\/"},"modified":"2026-02-05T21:04:08","modified_gmt":"2026-02-06T03:04:08","slug":"previews-in-headless-wordpress-using-nextjs","status":"publish","type":"post","link":"https:\/\/wpengine.com\/builders\/previews-in-headless-wordpress-using-nextjs\/","title":{"rendered":"Previews In Headless WordPress With NextJS"},"content":{"rendered":"\n<p>One of the first challenges you&#8217;ll face when you try out Headless WordPress is the lack of preview support. You cannot retrieve unpublished content through an API without the user authenticating first. On a traditional WordPress site, this isn&#8217;t an issue because the frontend is on the same domain as the backend, so you can use a cookie for authorization. When you use a frontend hosted on a separate domain from WordPress, your WordPress cookies will not work. To see unpublished content, you will need to set up a way to make authenticated requests to the WordPress API. This can be tricky because you do not want to allow unauthenticated users to see your unpublished content, so you need to avoid hard coding authentication secrets into your frontend code. This post will help you show you a few tools you can use to get previews working in NextJS.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Setting Up WordPress For Headless<\/h2>\n\n\n\n<p>If you haven\u2019t already, check out our post about <a href=\"https:\/\/wpengine.com\/builders\/how-to-set-up-wordpress-as-a-headless-cms\/\" target=\"_blank\" rel=\"noreferrer noopener\">setting up WordPress for headless<\/a>. For this post you will need to install and configure the following plugins (outlined in the post linked above):<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><a data-type=\"URL\" data-id=\"https:\/\/www.wpgraphql.com\/\" href=\"https:\/\/www.wpgraphql.com\/\" target=\"_blank\" rel=\"noreferrer noopener\">WPGraphQL<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/github.com\/wpengine\/faustjs\" target=\"_blank\" rel=\"noreferrer noopener\">Faust.js<\/a><\/li>\n<\/ol>\n\n\n\n<p>Make sure you follow the instructions in the post for configuring Faust.js. In the Faust.js settings (found in Settings > Faust), set <code>Front-end site URL<\/code> to <code>http:\/\/localhost:3000\/<\/code>. This will eventually be the URL where our frontend site is served.<\/p>\n\n\n\n<p>The next thing you will want to grab and store from the WPEngine Headless settings is the <code>Secret Key<\/code>. Below is an example screenshot that shows the Front-end site URL and Secret Key:<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img decoding=\"async\" src=\"https:\/\/wpengine.com\/builders\/wp-content\/uploads\/2021\/03\/headless-settings-auth-1.jpg\" alt=\"\" class=\"wp-image-95\"\/><\/figure>\n\n\n\n<p>Your Faust.js settings will look something like this. Make sure to note the Secret Key as you will need it later.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Building The Frontend Site With NextJS<\/h2>\n\n\n\n<p>Before building out your frontend site, you will need to make sure you have Node.js and NPM installed on your computer. If you are using a Mac, it is recommended that you install <a rel=\"noreferrer noopener\" href=\"https:\/\/github.com\/nvm-sh\/nvm\" data-type=\"URL\" data-id=\"https:\/\/github.com\/nvm-sh\/nvm\" target=\"_blank\">NVM<\/a>, which will help you manage your Node versions.<\/p>\n\n\n\n<p>Once you have Node and NPM installed on your machine, run the following commands:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-1\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php shcb-code-table shcb-line-numbers\"><span class='shcb-loc'><span>npx create-next-app previews\n<\/span><\/span><span class='shcb-loc'><span>cd previews\n<\/span><\/span><span class='shcb-loc'><span>rm -r .\/pages<span class=\"hljs-comment\">\/*<\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-comment\">npm i <span class=\"hljs-doctag\">@wpengine<\/span>\/headless <span class=\"hljs-doctag\">@apollo<\/span>\/client graphql<\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-comment\">npm i typescript <span class=\"hljs-doctag\">@types<\/span>\/react <span class=\"hljs-doctag\">@types<\/span>\/react-dom <span class=\"hljs-doctag\">@types<\/span>\/node -D<\/span>\n<\/span><\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-1\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Now your site is set up, but you still need to enable authentication with WordPress and build out a home page.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Authentication<\/h3>\n\n\n\n<p>To view previews in WordPress, you need to have higher access to your WordPress site. WordPress won&#8217;t show previews to you unless you are an authenticated user. You don&#8217;t notice this with a traditional WordPress site because the URL you preview posts typically shares the same domain and cookies as your WordPress admin panel. For headless WordPress, you have to find another way of authenticating and making requests for previews. This is where the WPEngine Headless plugin comes in handy.<\/p>\n\n\n\n<p>The WPEngine Headless plugin exposes routes that allow for an OAuth flow to obtain an access token used for authenticated requests such as previews. The flow looks as follows:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>User requests a secure route (i.e., draft post).<\/li>\n\n\n\n<li>User redirects to WordPress to login.<\/li>\n\n\n\n<li>WordPress redirects back to the frontend with a temporary code.<\/li>\n\n\n\n<li>The frontend server exchanges the code for an access token.<\/li>\n\n\n\n<li>The access token stores in a cookie.<\/li>\n\n\n\n<li>The user finally redirects back to the original URL and uses the access token in the cookie to make the authenticated request.<\/li>\n<\/ul>\n\n\n\n<p>Lucky for us, the @wpengine\/headless plugin provides a Node authorization handler to facilitate exchanging the authorization code for an access token, storing the token in a cookie, and redirecting back to the appropriate frontend route.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Authorization Handler<\/h3>\n\n\n\n<p>To take advantage of the authorization handler in your NextJS app with <code>@wpengine\/headless<\/code> you can create a new NextJS API route in <code>\/pages\/api\/auth\/wpe-headless.ts<\/code> with the following code:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-2\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-code-table shcb-line-numbers\"><span class='shcb-loc'><span><span class=\"hljs-keyword\">import<\/span> { authorizeHandler } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'@wpengine\/headless'<\/span>;\n<\/span><\/span><span class='shcb-loc'><span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">default<\/span> authorizeHandler;\n<\/span><\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-2\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p><code>authorizeHandler<\/code> accepts a Node request (i.e. <code>IncomingMessage<\/code>) and response (i.e., <code>ServerResponse<\/code>) and will work with any Node-based server library. This is all you need to get authentication working in your NextJS app. Now let\u2019s get started building out the application.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Building Your Frontend NextJS Page For Previews<\/h3>\n\n\n\n<p>NextJS is a React-based framework, and <code>@wpengine\/headless<\/code> is written to work alongside NextJS and React.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">HeadlessProvider<\/h4>\n\n\n\n<p>The first thing you need to do in order to integrate with <code>@wpengine\/headless<\/code> is invoke the <code>HeadlessProvider<\/code> in your <code>\/pages\/_app.tsx<\/code>. Use the following code:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-3\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-code-table shcb-line-numbers\"><span class='shcb-loc'><span><span class=\"hljs-keyword\">import<\/span> React <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'react'<\/span>;\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-keyword\">import<\/span> { AppContext, AppInitialProps } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'next\/app'<\/span>;\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-keyword\">import<\/span> { HeadlessProvider } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'@wpengine\/headless\/react'<\/span>;\n<\/span><\/span><span class='shcb-loc'><span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">default<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">App<\/span>(<span class=\"hljs-params\">{<\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-function\"><span class=\"hljs-params\">  Component,<\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-function\"><span class=\"hljs-params\">  pageProps,<\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-function\"><span class=\"hljs-params\">}: AppContext &amp; AppInitialProps<\/span>) <\/span>{\n<\/span><\/span><span class='shcb-loc'><span>  <span class=\"hljs-keyword\">return<\/span> (\n<\/span><\/span><span class='shcb-loc'><span>    <span class=\"xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">HeadlessProvider<\/span> <span class=\"hljs-attr\">pageProps<\/span>=<span class=\"hljs-string\">{pageProps}<\/span>&gt;<\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\">      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Component<\/span> {<span class=\"hljs-attr\">...pageProps<\/span>} \/&gt;<\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\">    <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">HeadlessProvider<\/span>&gt;<\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\">  );<\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\">}<\/span><\/span><\/span><\/span>\n<\/span><\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-3\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>The <code>HeadlessProvider<\/code> is the glue that allows the framework to communicate with WordPress. It needs to exist at the top level of your application wherever you want to hook into WordPress and take advantage of the GraphQL API.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Routes and Hooks<\/h4>\n\n\n\n<p>To support previews, you need two pages. One page handles all public routes (<code>\/pages\/[[\u2026page]].tsx<\/code>) and another will handle private preview routes (<code>\/pages\/preview\/[[\u2026page]].tsx<\/code>). <code>[[\u2026page]].tsx<\/code> is how you describe a catch-all route in Next. Put the following code in <code>\/pages\/[[\u2026page]].tsx<\/code>:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-4\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-code-table shcb-line-numbers\"><span class='shcb-loc'><span><span class=\"hljs-keyword\">import<\/span> React <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'react'<\/span>;\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-keyword\">import<\/span> {\n<\/span><\/span><span class='shcb-loc'><span>  useUriInfo,\n<\/span><\/span><span class='shcb-loc'><span>  getNextStaticPaths,\n<\/span><\/span><span class='shcb-loc'><span>  getNextStaticProps,\n<\/span><\/span><span class='shcb-loc'><span>} <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'@wpengine\/headless\/next'<\/span>;\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-keyword\">import<\/span> { GetStaticPropsContext } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'next'<\/span>;\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-keyword\">import<\/span> Posts <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'..\/lib\/components\/Posts'<\/span>;\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-keyword\">import<\/span> Post <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'..\/lib\/components\/Post'<\/span>;\n<\/span><\/span><span class='shcb-loc'><span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">default<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">Page<\/span>(<span class=\"hljs-params\"><\/span>) <\/span>{\n<\/span><\/span><span class='shcb-loc'><span>  <span class=\"hljs-keyword\">const<\/span> pageInfo = useUriInfo();\n<\/span><\/span><span class='shcb-loc'><span>\n<\/span><\/span><span class='shcb-loc'><span>  <span class=\"hljs-keyword\">if<\/span> (!pageInfo) {\n<\/span><\/span><span class='shcb-loc'><span>    <span class=\"hljs-keyword\">return<\/span> <span class=\"xml\"><span class=\"hljs-tag\">&lt;&gt;<\/span><span class=\"hljs-tag\">&lt;\/&gt;<\/span><\/span>;\n<\/span><\/span><span class='shcb-loc'><span>  }\n<\/span><\/span><span class='shcb-loc'><span>\n<\/span><\/span><span class='shcb-loc'><span>  <span class=\"hljs-keyword\">if<\/span> (pageInfo.isPostsPage) {\n<\/span><\/span><span class='shcb-loc'><span>    <span class=\"hljs-keyword\">return<\/span> <span class=\"xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Posts<\/span> \/&gt;<\/span><\/span>;\n<\/span><\/span><span class='shcb-loc'><span>  }\n<\/span><\/span><span class='shcb-loc'><span>\n<\/span><\/span><span class='shcb-loc'><span>  <span class=\"hljs-keyword\">return<\/span> <span class=\"xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Post<\/span> \/&gt;<\/span><\/span>;\n<\/span><\/span><span class='shcb-loc'><span>}\n<\/span><\/span><span class='shcb-loc'><span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">getStaticPaths<\/span>(<span class=\"hljs-params\"><\/span>) <\/span>{\n<\/span><\/span><span class='shcb-loc'><span>  <span class=\"hljs-keyword\">return<\/span> getNextStaticPaths();\n<\/span><\/span><span class='shcb-loc'><span>}\n<\/span><\/span><span class='shcb-loc'><span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">getStaticProps<\/span>(<span class=\"hljs-params\">context: GetStaticPropsContext<\/span>) <\/span>{\n<\/span><\/span><span class='shcb-loc'><span>  <span class=\"hljs-keyword\">return<\/span> getNextStaticProps(context);\n<\/span><\/span><span class='shcb-loc'><span>}\n<\/span><\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-4\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Ignore the errors you get about <code>&lt;Posts \/&gt;<\/code> and <code>&lt;Post \/&gt;<\/code> for now, we will create those components soon. A couple interesting things to note with this component:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><code>getNextStaticProps<\/code> is used to enable Static Site Generation (SSG) with Next. It knows how to get the URL information on the server-side and make the necessary query for a list or single post. It will then cache the queries so the queries can be used client-side without making network requests. This is crucial for site performance and SEO.<\/li>\n\n\n\n<li><code>useUriInfo<\/code> is a hook provided by <code>@wpengine\/headless<\/code>. It will get the current URL and query the WordPress GraphQL API to get information about the URL. If the route has a list of posts (i.e. <code>pageInfo.isPostsPage<\/code> we\u2019ll show the <code>Posts<\/code> component, otherwise we show the <code>Post<\/code> component.<\/li>\n<\/ol>\n\n\n\n<p>Let\u2019s create the <code>Post<\/code> component. In <code>\/lib\/components\/Post.tsx<\/code> place the following code:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-5\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-code-table shcb-line-numbers\"><span class='shcb-loc'><span><span class=\"hljs-keyword\">import<\/span> React <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'react'<\/span>;\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-keyword\">import<\/span> { usePost } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'@wpengine\/headless\/next'<\/span>;\n<\/span><\/span><span class='shcb-loc'><span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">default<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">Post<\/span>(<span class=\"hljs-params\"><\/span>) <\/span>{\n<\/span><\/span><span class='shcb-loc'><span>  <span class=\"hljs-keyword\">const<\/span> post = usePost();\n<\/span><\/span><span class='shcb-loc'><span>\n<\/span><\/span><span class='shcb-loc'><span>  <span class=\"hljs-keyword\">return<\/span> (\n<\/span><\/span><span class='shcb-loc'><span>    <span class=\"xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span>&gt;<\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\">      {post &amp;&amp; (<\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\">        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span>&gt;<\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\">          <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span>&gt;<\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\">            <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">h5<\/span>&gt;<\/span>{post.title}<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">h5<\/span>&gt;<\/span><\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\">            <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\">              <span class=\"hljs-attr\">dangerouslySetInnerHTML<\/span>=<span class=\"hljs-string\">{{<\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\">                <span class=\"hljs-attr\">__html:<\/span> <span class=\"hljs-attr\">post.content<\/span> ?? '',<\/span><\/span><\/span><\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\">              }}<\/span><\/span><\/span><\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\">            \/&gt;<\/span><\/span><\/span><\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\">          <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span><\/span><\/span><\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\">        <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\">      )}<\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\">    <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\">  );<\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\">}<\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span>\n<\/span><\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-5\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>The component above is used to render an individual post. It takes advantage of the <code>usePost<\/code> hook provided by <code>@wpengine\/headless<\/code>.<\/p>\n\n\n\n<p>Next, let\u2019s create the <code>Posts<\/code> component. In <code>\/lib\/components\/Posts.tsx<\/code> put the following code:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-6\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-code-table shcb-line-numbers\"><span class='shcb-loc'><span><span class=\"hljs-keyword\">import<\/span> React <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'react'<\/span>;\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-keyword\">import<\/span> Link <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'next\/link'<\/span>;\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-keyword\">import<\/span> { usePosts } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'@wpengine\/headless\/react'<\/span>;\n<\/span><\/span><span class='shcb-loc'><span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">default<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">Posts<\/span>(<span class=\"hljs-params\"><\/span>) <\/span>{\n<\/span><\/span><span class='shcb-loc'><span>  <span class=\"hljs-keyword\">const<\/span> posts = usePosts();\n<\/span><\/span><span class='shcb-loc'><span>\n<\/span><\/span><span class='shcb-loc'><span>  <span class=\"hljs-keyword\">return<\/span> (\n<\/span><\/span><span class='shcb-loc'><span>    <span class=\"xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span>&gt;<\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\">      {posts &amp;&amp;<\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\">        posts.nodes.map((post) =&gt; (<\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\">          <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">key<\/span>=<span class=\"hljs-string\">{post.id}<\/span> <span class=\"hljs-attr\">id<\/span>=<span class=\"hljs-string\">{<\/span>`<span class=\"hljs-attr\">post-<\/span>${<span class=\"hljs-attr\">post.id<\/span>}`}&gt;<\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\">            <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span>&gt;<\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\">              <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Link<\/span> <span class=\"hljs-attr\">href<\/span>=<span class=\"hljs-string\">{post.uri}<\/span>&gt;<\/span><\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\">                <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">h5<\/span>&gt;<\/span><\/span><\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\">                  <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">a<\/span> <span class=\"hljs-attr\">href<\/span>=<span class=\"hljs-string\">{post.uri}<\/span>&gt;<\/span>{post.title}<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">a<\/span>&gt;<\/span><\/span><\/span><\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\">                <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">h5<\/span>&gt;<\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\">              <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">Link<\/span>&gt;<\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\">              <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\">                <span class=\"hljs-attr\">dangerouslySetInnerHTML<\/span>=<span class=\"hljs-string\">{{<\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\">                  <span class=\"hljs-attr\">__html:<\/span> <span class=\"hljs-attr\">post.excerpt<\/span> ?? '',<\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\">                }}<\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\">              \/&gt;<\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\">            <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\">          <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\">        ))}<\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\">    <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\">  );<\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\">}<\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span>\n<\/span><\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-6\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>The component above is used to render a list of posts. It uses the <code>usePosts<\/code> hook provided by <code>@wpengine\/headless<\/code> to get the appropriate list of posts.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Running The Application<\/h3>\n\n\n\n<p>Now you should have a public page to display both a list of posts. Before you can run it, you will need to configure a <code>.env.local<\/code> file with the appropriate environment variables needed by <code>@wpengine\/headless<\/code>. Create a file in the root of your project called <code>.env.local<\/code> and configure it as follows:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-7\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php shcb-code-table shcb-line-numbers\"><span class='shcb-loc'><span><span class=\"hljs-comment\"># Base URL for WordPress<\/span>\n<\/span><\/span><span class='shcb-loc'><span>NEXT_PUBLIC_WORDPRESS_URL=http:<span class=\"hljs-comment\">\/\/yourwpsite.com<\/span>\n<\/span><\/span><span class='shcb-loc'><span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-comment\"># Plugin secret found in WordPress Settings-&gt;Headless<\/span>\n<\/span><\/span><span class='shcb-loc'><span>WP_HEADLESS_SECRET=YOUR_PLUGIN_SECRET\n<\/span><\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-7\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>You will need to set the <code>NEXT_PUBLIC_WORDPRESS_URL<\/code> to the root URL of your WordPress site. If you remember earlier in this post, you were asked to save your <code>Secret Key<\/code> from your WordPress headless settings, that should go in your <code>.env.local<\/code> as your <code>WP_HEADLESS_SECRET<\/code> value.<\/p>\n\n\n\n<p><strong>NOTE: <\/strong>It is important to only put <code>NEXT_PUBLIC_<\/code> in front of environment variables if you intend for them to be available to the client. You do not want <code>WP_HEADLESS_SECRET<\/code> visible to the client, so it does not need the prefix.<\/p>\n\n\n\n<p>Now that you have your <code>.env.local<\/code> configured, run your site with the following command:<\/p>\n\n\n<pre class=\"wp-block-code\"><span><code class=\"hljs shcb-code-table shcb-line-numbers\"><span class='shcb-loc'><span>npm run dev\n<\/span><\/span><\/code><\/span><\/pre>\n\n\n<p>A Node server will start on port 3000 by default: <a rel=\"noreferrer noopener\" href=\"http:\/\/localhost:3000\" target=\"_blank\">http:\/\/localhost:3000<\/a>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Adding A Page For Previews<\/h3>\n\n\n\n<p>After verifying that your site works and you can see a list of posts and individual posts, the last step is to set up a page for previews. Create a file called <code>\/pages\/preview\/[[\u2026page]].tsx<\/code> and put the following code in it:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-8\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-code-table shcb-line-numbers\"><span class='shcb-loc'><span><span class=\"hljs-keyword\">import<\/span> React <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'react'<\/span>;\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-keyword\">import<\/span> Post <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'..\/lib\/components\/Post'<\/span>;\n<\/span><\/span><span class='shcb-loc'><span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">default<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">Page<\/span>(<span class=\"hljs-params\"><\/span>) <\/span>{\n<\/span><\/span><span class='shcb-loc'><span>  <span class=\"hljs-keyword\">return<\/span> <span class=\"xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Post<\/span> \/&gt;<\/span><\/span>;\n<\/span><\/span><span class='shcb-loc'><span>}\n<\/span><\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-8\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>The code for previews is a little bit cleaner than the public page, and for good reason. You only need to preview individual posts, so there is no need to do anything else. Also, note that the preview page does not use <code>getStaticProps<\/code> or <code>getStaticPaths<\/code>. This is intentional, as we only need to get previews client-side.<\/p>\n\n\n\n<p>Now that you have this component in place, you can run your site and then test if previews work by going to your list of posts in <code>wp-admin<\/code> and clicking to preview a draft post (you might have to create a draft post if you don\u2019t have one already).<\/p>\n\n\n\n<p>That\u2019s all there is to it, you have successfully set up a headless WordPress site with a NextJS frontend, and you can preview unpublished posts!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>One of the first challenges you&#8217;ll face when you try out Headless WordPress is the lack of preview support. You cannot retrieve unpublished content through an API without the user [&hellip;]<\/p>\n","protected":false},"author":22,"featured_media":92,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_EventAllDay":false,"_EventTimezone":"","_EventStartDate":"","_EventEndDate":"","_EventStartDateUTC":"","_EventEndDateUTC":"","_EventShowMap":false,"_EventShowMapLink":false,"_EventURL":"","_EventCost":"","_EventCostDescription":"","_EventCurrencySymbol":"","_EventCurrencyCode":"","_EventCurrencyPosition":"","_EventDateTimeSeparator":"","_EventTimeRangeSeparator":"","_EventOrganizerID":[],"_EventVenueID":[],"_OrganizerEmail":"","_OrganizerPhone":"","_OrganizerWebsite":"","_VenueAddress":"","_VenueCity":"","_VenueCountry":"","_VenueProvince":"","_VenueState":"","_VenueZip":"","_VenuePhone":"","_VenueURL":"","_VenueStateProvince":"","_VenueLat":"","_VenueLng":"","_VenueShowMap":false,"_VenueShowMapLink":false,"footnotes":""},"categories":[23],"tags":[],"class_list":["post-5185","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-headless"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.4 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Previews In Headless WordPress With NextJS - Builders<\/title>\n<meta name=\"description\" content=\"Learn how to develop WordPress previews in a headless state using NextJS. Close the gap between headless development and content management.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/wpengine.com\/builders\/previews-in-headless-wordpress-using-nextjs\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Previews In Headless WordPress With NextJS - Builders\" \/>\n<meta property=\"og:description\" content=\"Learn how to develop WordPress previews in a headless state using NextJS. Close the gap between headless development and content management.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/wpengine.com\/builders\/previews-in-headless-wordpress-using-nextjs\/\" \/>\n<meta property=\"og:site_name\" content=\"Builders\" \/>\n<meta property=\"article:published_time\" content=\"2021-03-02T09:36:14+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2026-02-06T03:04:08+00:00\" \/>\n<meta name=\"author\" content=\"Will Johnston\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@wpebuilders\" \/>\n<meta name=\"twitter:site\" content=\"@wpebuilders\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Will Johnston\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"6 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/wpengine.com\\\/builders\\\/previews-in-headless-wordpress-using-nextjs\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/wpengine.com\\\/builders\\\/previews-in-headless-wordpress-using-nextjs\\\/\"},\"author\":{\"name\":\"Will Johnston\",\"@id\":\"https:\\\/\\\/wpengine.com\\\/builders\\\/#\\\/schema\\\/person\\\/12c2a773cdc5451ead7cb8c7f2f1fd83\"},\"headline\":\"Previews In Headless WordPress With NextJS\",\"datePublished\":\"2021-03-02T09:36:14+00:00\",\"dateModified\":\"2026-02-06T03:04:08+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/wpengine.com\\\/builders\\\/previews-in-headless-wordpress-using-nextjs\\\/\"},\"wordCount\":1280,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\\\/\\\/wpengine.com\\\/builders\\\/#organization\"},\"image\":{\"@id\":\"https:\\\/\\\/wpengine.com\\\/builders\\\/previews-in-headless-wordpress-using-nextjs\\\/#primaryimage\"},\"thumbnailUrl\":\"\",\"articleSection\":[\"Headless\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/wpengine.com\\\/builders\\\/previews-in-headless-wordpress-using-nextjs\\\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/wpengine.com\\\/builders\\\/previews-in-headless-wordpress-using-nextjs\\\/\",\"url\":\"https:\\\/\\\/wpengine.com\\\/builders\\\/previews-in-headless-wordpress-using-nextjs\\\/\",\"name\":\"Previews In Headless WordPress With NextJS - Builders\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/wpengine.com\\\/builders\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/wpengine.com\\\/builders\\\/previews-in-headless-wordpress-using-nextjs\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/wpengine.com\\\/builders\\\/previews-in-headless-wordpress-using-nextjs\\\/#primaryimage\"},\"thumbnailUrl\":\"\",\"datePublished\":\"2021-03-02T09:36:14+00:00\",\"dateModified\":\"2026-02-06T03:04:08+00:00\",\"description\":\"Learn how to develop WordPress previews in a headless state using NextJS. Close the gap between headless development and content management.\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/wpengine.com\\\/builders\\\/previews-in-headless-wordpress-using-nextjs\\\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/wpengine.com\\\/builders\\\/previews-in-headless-wordpress-using-nextjs\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/wpengine.com\\\/builders\\\/previews-in-headless-wordpress-using-nextjs\\\/#primaryimage\",\"url\":\"\",\"contentUrl\":\"\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/wpengine.com\\\/builders\\\/previews-in-headless-wordpress-using-nextjs\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/wpengine.com\\\/builders\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Previews In Headless WordPress With NextJS\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/wpengine.com\\\/builders\\\/#website\",\"url\":\"https:\\\/\\\/wpengine.com\\\/builders\\\/\",\"name\":\"Builders\",\"description\":\"Reimagining the way we build with WordPress.\",\"publisher\":{\"@id\":\"https:\\\/\\\/wpengine.com\\\/builders\\\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/wpengine.com\\\/builders\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\\\/\\\/wpengine.com\\\/builders\\\/#organization\",\"name\":\"WP Engine\",\"url\":\"https:\\\/\\\/wpengine.com\\\/builders\\\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/wpengine.com\\\/builders\\\/#\\\/schema\\\/logo\\\/image\\\/\",\"url\":\"https:\\\/\\\/wpengine.com\\\/builders\\\/wp-content\\\/uploads\\\/2024\\\/05\\\/WP-Engine-Horizontal@2x.png\",\"contentUrl\":\"https:\\\/\\\/wpengine.com\\\/builders\\\/wp-content\\\/uploads\\\/2024\\\/05\\\/WP-Engine-Horizontal@2x.png\",\"width\":348,\"height\":68,\"caption\":\"WP Engine\"},\"image\":{\"@id\":\"https:\\\/\\\/wpengine.com\\\/builders\\\/#\\\/schema\\\/logo\\\/image\\\/\"},\"sameAs\":[\"https:\\\/\\\/x.com\\\/wpebuilders\",\"https:\\\/\\\/www.youtube.com\\\/channel\\\/UCh1WuL54XFb9ZI6m6goFv1g\"]},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/wpengine.com\\\/builders\\\/#\\\/schema\\\/person\\\/12c2a773cdc5451ead7cb8c7f2f1fd83\",\"name\":\"Will Johnston\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/711cc598460b8cfa41e03d26343818356d4c0560269da54d2ac27bece492cd50?s=96&d=mm&r=g\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/711cc598460b8cfa41e03d26343818356d4c0560269da54d2ac27bece492cd50?s=96&d=mm&r=g\",\"contentUrl\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/711cc598460b8cfa41e03d26343818356d4c0560269da54d2ac27bece492cd50?s=96&d=mm&r=g\",\"caption\":\"Will Johnston\"},\"url\":\"https:\\\/\\\/wpengine.com\\\/builders\\\/author\\\/wjohnsto\\\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Previews In Headless WordPress With NextJS - Builders","description":"Learn how to develop WordPress previews in a headless state using NextJS. Close the gap between headless development and content management.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/wpengine.com\/builders\/previews-in-headless-wordpress-using-nextjs\/","og_locale":"en_US","og_type":"article","og_title":"Previews In Headless WordPress With NextJS - Builders","og_description":"Learn how to develop WordPress previews in a headless state using NextJS. Close the gap between headless development and content management.","og_url":"https:\/\/wpengine.com\/builders\/previews-in-headless-wordpress-using-nextjs\/","og_site_name":"Builders","article_published_time":"2021-03-02T09:36:14+00:00","article_modified_time":"2026-02-06T03:04:08+00:00","author":"Will Johnston","twitter_card":"summary_large_image","twitter_creator":"@wpebuilders","twitter_site":"@wpebuilders","twitter_misc":{"Written by":"Will Johnston","Est. reading time":"6 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/wpengine.com\/builders\/previews-in-headless-wordpress-using-nextjs\/#article","isPartOf":{"@id":"https:\/\/wpengine.com\/builders\/previews-in-headless-wordpress-using-nextjs\/"},"author":{"name":"Will Johnston","@id":"https:\/\/wpengine.com\/builders\/#\/schema\/person\/12c2a773cdc5451ead7cb8c7f2f1fd83"},"headline":"Previews In Headless WordPress With NextJS","datePublished":"2021-03-02T09:36:14+00:00","dateModified":"2026-02-06T03:04:08+00:00","mainEntityOfPage":{"@id":"https:\/\/wpengine.com\/builders\/previews-in-headless-wordpress-using-nextjs\/"},"wordCount":1280,"commentCount":0,"publisher":{"@id":"https:\/\/wpengine.com\/builders\/#organization"},"image":{"@id":"https:\/\/wpengine.com\/builders\/previews-in-headless-wordpress-using-nextjs\/#primaryimage"},"thumbnailUrl":"","articleSection":["Headless"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/wpengine.com\/builders\/previews-in-headless-wordpress-using-nextjs\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/wpengine.com\/builders\/previews-in-headless-wordpress-using-nextjs\/","url":"https:\/\/wpengine.com\/builders\/previews-in-headless-wordpress-using-nextjs\/","name":"Previews In Headless WordPress With NextJS - Builders","isPartOf":{"@id":"https:\/\/wpengine.com\/builders\/#website"},"primaryImageOfPage":{"@id":"https:\/\/wpengine.com\/builders\/previews-in-headless-wordpress-using-nextjs\/#primaryimage"},"image":{"@id":"https:\/\/wpengine.com\/builders\/previews-in-headless-wordpress-using-nextjs\/#primaryimage"},"thumbnailUrl":"","datePublished":"2021-03-02T09:36:14+00:00","dateModified":"2026-02-06T03:04:08+00:00","description":"Learn how to develop WordPress previews in a headless state using NextJS. Close the gap between headless development and content management.","breadcrumb":{"@id":"https:\/\/wpengine.com\/builders\/previews-in-headless-wordpress-using-nextjs\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/wpengine.com\/builders\/previews-in-headless-wordpress-using-nextjs\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/wpengine.com\/builders\/previews-in-headless-wordpress-using-nextjs\/#primaryimage","url":"","contentUrl":""},{"@type":"BreadcrumbList","@id":"https:\/\/wpengine.com\/builders\/previews-in-headless-wordpress-using-nextjs\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/wpengine.com\/builders\/"},{"@type":"ListItem","position":2,"name":"Previews In Headless WordPress With NextJS"}]},{"@type":"WebSite","@id":"https:\/\/wpengine.com\/builders\/#website","url":"https:\/\/wpengine.com\/builders\/","name":"Builders","description":"Reimagining the way we build with WordPress.","publisher":{"@id":"https:\/\/wpengine.com\/builders\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/wpengine.com\/builders\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/wpengine.com\/builders\/#organization","name":"WP Engine","url":"https:\/\/wpengine.com\/builders\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/wpengine.com\/builders\/#\/schema\/logo\/image\/","url":"https:\/\/wpengine.com\/builders\/wp-content\/uploads\/2024\/05\/WP-Engine-Horizontal@2x.png","contentUrl":"https:\/\/wpengine.com\/builders\/wp-content\/uploads\/2024\/05\/WP-Engine-Horizontal@2x.png","width":348,"height":68,"caption":"WP Engine"},"image":{"@id":"https:\/\/wpengine.com\/builders\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/x.com\/wpebuilders","https:\/\/www.youtube.com\/channel\/UCh1WuL54XFb9ZI6m6goFv1g"]},{"@type":"Person","@id":"https:\/\/wpengine.com\/builders\/#\/schema\/person\/12c2a773cdc5451ead7cb8c7f2f1fd83","name":"Will Johnston","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/secure.gravatar.com\/avatar\/711cc598460b8cfa41e03d26343818356d4c0560269da54d2ac27bece492cd50?s=96&d=mm&r=g","url":"https:\/\/secure.gravatar.com\/avatar\/711cc598460b8cfa41e03d26343818356d4c0560269da54d2ac27bece492cd50?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/711cc598460b8cfa41e03d26343818356d4c0560269da54d2ac27bece492cd50?s=96&d=mm&r=g","caption":"Will Johnston"},"url":"https:\/\/wpengine.com\/builders\/author\/wjohnsto\/"}]}},"_links":{"self":[{"href":"https:\/\/wpengine.com\/builders\/wp-json\/wp\/v2\/posts\/5185","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/wpengine.com\/builders\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/wpengine.com\/builders\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/wpengine.com\/builders\/wp-json\/wp\/v2\/users\/22"}],"replies":[{"embeddable":true,"href":"https:\/\/wpengine.com\/builders\/wp-json\/wp\/v2\/comments?post=5185"}],"version-history":[{"count":0,"href":"https:\/\/wpengine.com\/builders\/wp-json\/wp\/v2\/posts\/5185\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/wpengine.com\/builders\/wp-json\/"}],"wp:attachment":[{"href":"https:\/\/wpengine.com\/builders\/wp-json\/wp\/v2\/media?parent=5185"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/wpengine.com\/builders\/wp-json\/wp\/v2\/categories?post=5185"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/wpengine.com\/builders\/wp-json\/wp\/v2\/tags?post=5185"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}