To get live preview working, we will need to make changes in two places. First, we’ll update our Next.js app with the appropriate queries, followed by a few small changes to our Craft CMS set up.
If you haven’t set up Craft CMS with Next.js already, I advise you read through my previous article before starting this one.
Updating Next.js
In your Next.js .env
file, set up some new variables we will use.
# match your API endpoint URL here
CRAFT_CMS_GRAPHQL_ENDPOINT=http://your-site.com/api
# not always needed, but added in case you use a limited scope.
CRAFT_CMS_GRAPHQL_TOKEN=
In a utility file (/util/getApiQuery.ts
), let’s set up the code for talking to our GraphQL endpoint and ensuring that it returns the appropriate data.
interface IHeaders {
"Content-Type": string
Authorization: string
[k: string]: any
}
export async function getApiQuery(
query: string,
variables?: Object | {},
preview?: string | string[] | undefined,
) {
const endpoints = `${process.env.CRAFT_CMS_GRAPHQL_ENDPOINT}`
// If we have a preview token, adapt our
// endpoint to feature the x-craft-live-preview stucture.
const src = preview ? `${endpoints}?x-craft-live-preview=${preview}` : endpoint
// Set the necessary headers
const headers: IHeaders = {
"Content-Type": "application/json",
Authorization: `Bearer ${process.env.CRAFT_CMS_GRAPHQL_TOKEN}`,
}
// If we're on a preview, set the craft token header which
// is pulled from the query string
if (preview) {
headers['x-craft-token'] = preview
}
// Handle the fetch
const res = await fetch(src, {
method: "POST",
body: JSON.stringify({
query,
variables,
}),
headers: headers
})
if (!res.ok) {
throw new Error("Failed to fetch data from API")
}
const json = await res.json()
return json?.data
}
If you already have a method of fetching data, the important parts here are dynamically setting our endpoint.
const endpoints = `${process.env.CRAFT_CMS_GRAPHQL_ENDPOINT}`
const src = preview ? `${endpoints}?x-craft-live-preview=${preview}` : endpoint
And, updating our headers.
const headers: IHeaders = {
"Content-Type": "application/json",
Authorization: `Bearer ${process.env.CRAFT_CMS_GRAPHQL_TOKEN}`,
}
if (preview) {
headers['x-craft-token'] = preview
}
Next, inside of one of our pages, e.g. /app/page.tsx
, we need to fetch any of the search parameters to ensure we can check for the token. We can do this by updating our main function.
If the searchParams[‘token’]
exists, and if not, set it to a blank string. Then, we pass it through to a getData
function.
const Page = async ({
searchParams,
}: {
searchParams: { [key: string]: string | string[] | undefined }
}) => {
const preview = searchParams['token'] || ''
const { title } = await getData(preview)
}) {
return <>{title}</>
}
export default Page
Inside our getData
function, we need to make sure we are passing through the appropriate preview
(token) string.
To do this, we will pass it through to our getApiQuery
function we created earlier, and everything else will be handled there.
async function getData(preview?: string | string[] | undefined) {
// Your GraphQL query, ideally stored in a seperate file.
const query = `
query AboutQuery {
aboutEntries {
title
}
}
`
// Example call passing.
const { aboutEntries } = await getApiQuery(query, {}, preview)
// Return the data
return aboutEntries[0]
}
Updating Craft CMS
To ensure our preview URLs are being sent over to the right place, we will need to tweak each section’s preview targets.
Let’s set up a few alias so we can update these appropriately per environment. In config/general.php
update the aliases:
<?php
use craft\config\GeneralConfig;
return GeneralConfig::create()
// rest of your code here
->aliases([
'@webroot' => dirname(__DIR__) . '/web',
'@preview' => getenv('PREVIEW_URL'),
]);
In our Craft .env
add the following:
PREVIEW_URL=https://localhost:3000
Then, in each section you want to enable Live Preview for, update the preview targets to reference the alias we just made, like so {{ alias('@preview') }}/{uri}
.
That’s it for the Craft side. Now, if you head to an entry, you should be able to click “Live Preview” and see everything rendering.
Round up
Perfect, so just to clarify a little about everything that we have been through:
- When our site is requested through Craft’s live preview, it will pass through a couple of query parameters to the URL it calls, one which is
token
. - We’ll then use these to define the way we fetch the data from the endpoint, by conditionally rendering extra headers and updating our source URL.
- The data will be loaded into our view and render the content as appropriate, because Craft handles the rest on the GraphQL side.
Hope this helps you, if you have any issues let me know on Mastodon.