Add dynamic pages
Welcome to the fourth article in the getting started with Prismic & Gatsby tutorial series. We'll be walking through the steps to convert the repeatable pages from being hardcoded to being dynamically created and filled with content from Prismic.
🕙 Before reading
If you haven't already gone through the first step, we recommend you start there to download the project, launch a Prismic repository, and install the required plugin and dependencies.
Re-launch your site by running npm start. Looking at the two extra pages: /about and /more-info, you can see that we can re-use the same Slice Zone model and code components that we created in the previous article.
This model has already been put into place in your Prismic repository, so let's take a look at it now. Go to your Prismic repo, click on the Custom Types button in the left-hand navigation, then select your Page type. Here you can see how the Slice Zone is configured the same as the Homepage Slice Zone.
⚠️ No need to modify the Custom types
You do not need to change anything in the Custom types of your repository. Just take a look at how it is set up. If you wish to change anything, we highly recommend you wait until the end of this step by step tutorial.
The only difference between the Page vs the Homepage model is that we exclude the banner and add a UID field, a URL-friendly unique ID that we will use to determine our pages' URLs, and use to query the document when that page is visited.
Run the project with npm start and look at your API Explorer at http://localhost:8000/__graphql. Once there, input this GraphQL query and its variable in the left-hand panel:
- Query variables
- GraphQL query
{
"uid": "about"
}
query PageQuery($uid: String) {
allPrismicPage(filter: {uid: {eq: $uid}}) {
edges {
node {
uid
data {
body {
... on PrismicPageBodyText {
slice_type
primary {
columns
content {
raw
}
}
}
... on PrismicPageBodyQuote {
slice_type
primary {
quote {
raw
}
}
}
... on PrismicPageBodyFullWidthImage {
slice_type
primary {
full_width_image {
url
thumbnails
}
}
}
... on PrismicPageBodyImageGallery {
slice_type
primary {
gallery_title {
raw
}
}
items {
image {
url
thumbnails
alt
}
image_description {
raw
}
link {
url
type
uid
}
link_label {
raw
}
}
}
... on PrismicPageBodyImageHighlight {
slice_type
primary {
featured_image {
url
thumbnails
alt
}
title {
raw
}
description {
raw
}
link {
url
type
uid
}
link_label {
raw
}
}
}
}
}
}
}
}
}
You can run the query by pressing the "play" button ▷ at the top, showing you the query results on the right. Read, Anatomy of a query. There are a few important things to note here:
- The Page's Custom Type is repeatable, so we need to query the documents based on the URL visited. That's why we need the $uid variable in the query. Read more about querying by UID here.
- In the GraphiQL explorer, you need to specify the uid variable value, but this is automatically generated during the site build in your project.
Let's now programmatically create pages from data.
Before we create the page template, delete the /src/pages/about.js and /src/pages/more-info.js files.
⚠️ Don't skip this step
If you skip this step, you'll end up with errors in the next step.
We will use Gatsby's API 'createPages' method. Create a new gatsby-node.js file at the root of your project and paste this code:
const path = require('path')
exports.createPages = async ({ graphql, actions }) => {
const { createPage } = actions
const pages = await graphql(`
{
allPrismicPage {
nodes {
id
uid
lang
type
url
}
}
}
`)
pages.data.allPrismicPage.nodes.forEach((page) => {
createPage({
path: page.url,
component: path.resolve(__dirname, 'src/templates/Page.js'),
context: { ...page },
})
})
}
This will handle any dynamic pages we want to generate from Prismic. For each existing page, the createPage method will generate:
- path: The path URL for each page. This is generated using the UID of each page.
- component: The route where the template will be located.
- context: The automatically created pages can receive context and use that as variables in their GraphQL queries.
Learn more about programmatically generating pages with Gatsby.
If you try to re-build your website at this point, your build will fail because we haven't created the Page template component yet that we defined in the config above.
In the src folder, create a new folder and name it templates, then add a Page.js file inside. This should create the file we specified in the config above: src/templates/Page.js.
Copy and paste the following code into Page.js.
import React from 'react'
import { graphql } from 'gatsby'
import Layout from '../components/Layout'
import SEO from '../components/SEO'
import SliceZone from '../components/SliceZone'
const Page = ({ data }) => {
if (!data) return null
const document = data.allPrismicPage.edges[0].node
const capitalizeFirstLetter = (input) => {
return input[0].toUpperCase() + input.slice(1)
}
return (
<Layout>
<SEO title={capitalizeFirstLetter(document.uid)} />
<SliceZone sliceZone={document.data.body} />
</Layout>
)
}
export const query = graphql`
query PageQuery($uid: String) {
allPrismicPage(filter: { uid: { eq: $uid } }) {
edges {
node {
uid
data {
body {
... on PrismicPageBodyText {
slice_type
primary {
columns
content {
raw
}
}
}
... on PrismicPageBodyQuote {
slice_type
primary {
quote {
raw
}
}
}
... on PrismicPageBodyFullWidthImage {
slice_type
primary {
full_width_image {
url
thumbnails
}
}
}
... on PrismicPageBodyImageGallery {
slice_type
primary {
gallery_title {
raw
}
}
items {
image {
url
thumbnails
alt
}
image_description {
raw
}
link {
url
type
uid
}
link_label {
raw
}
}
}
... on PrismicPageBodyImageHighlight {
slice_type
primary {
featured_image {
url
thumbnails
alt
}
title {
raw
}
description {
raw
}
link {
url
type
uid
}
link_label {
raw
}
}
}
}
}
}
}
}
}
`
export default Page
Now let's rebuild the site and see our new pages. In your terminal, stop the current Gatsby server by pressing CTRL + C. Then relaunch your server by running npm start. When the build is complete, the "About" and "More Info" pages are now pulling their content entirely from Prismic!
Next up, we will be updating the project to have the ability to control the top navigation from Prismic.