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.

See the Pages model

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.

Look at the content model in Prismic

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 content model in Prismic

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.

1. Test the Page query

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
Copy
{
  "uid": "about"
}
Copy
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.

2. Render the results

Let's now programmatically create pages from data.

1. Delete the hardcoded pages

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.

2. Create dynamic pages

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:

Copy
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.

3. Create the page template

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.

Copy
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 steps

Next up, we will be updating the project to have the ability to control the top navigation from Prismic.

Adding the navigation →

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.