Adding repeatable pages

Prismic no longer recommends the gatsby-source-prismic-graphql plugin

With recent changes to Gatsby, Prismic no longer recommends the gatsby-source-prismic-graphql plugin that this documentation uses. Read more about the future of Prismic and Gatsby. We highly recommend using the gatsby-source-prismic instead. The documentation for this plugin can be found in the plugin's github README.

We will leave this documentation here for now, but will change it in the future when we determine the best approach for Prismic & Gatsby.

Welcome to the 4th article in the Gatsby/Prismic Getting started tutorial series. We'll be walking through the steps required to convert the repeatable pages from being hardcoded in your Gatsby app to being dynamically created and filled with content from Prismic.

Before reading

If you haven't already gone through the first three articles in this series, we recommend starting with the first article and work your way to this one. After that, this article will make much more sense.

Model the Pages in Prismic

We are working with the assumption that all the content of the pages needs to be easily modifiable. That is, we want to make it so that our content authors can mix-and-match the various page elements to build the pages just like the main content in our Homepage from the last article.

Review the page content

If you don't already have your website running, then open a terminal at the root of your project and run the npm start command to build and launch the site. Looking at the two extra pages, you can see that they are made up of the same page components as our homepage main content section.

This is great because 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 exactly the same as the Homepage Slice Zone.

The content model in Prismic

The only difference between the Page model and the Homepage model, is that we are excluding the homepage banner and adding a new field called the UID field. You can read more about it in our UID field documentation, but basically it is a URL-friendly unique ID that we will use to determine our pages' urls and it will be what we use to query the document when that page is visited.

Update the config for the repeatable pages

Now let's switch to your project code and get started there. In your project files, open the gatsby-config.js file. We need to update the gatsby-source-prismic-graphql configuration to include the repeatable pages.

Below you can find what the new configuration will look like. The first tab is the updated config for our plugin, the second tab shows you the updated config in the full gatsby-config.js file.

Update the repository name

Make sure that you keep the repositoryName the same as it is. If you accidentally copy & paste 'your-repo-name', you will need to update the value with your Prismic repository ID. In order to find this, go to your Prismic repository. For example, if the url for your repository is https://my-awesome-repository.prismic.io/ then you'll need to replace 'your-repo-name' below with 'my-awesome-repository'.

  • Updated config
  • Full gatsby-config.js file
Copy
{
  resolve: '@prismicio/gatsby-source-prismic-graphql',
  options: {
    repositoryName: 'your-repo-name',
    pages: [{
      type: 'Page',
      match: '/:uid',
      path: '/page-preview',
      component: require.resolve('./src/templates/Page.js'),
    }],
  },
}
Copy
module.exports = {
  siteMetadata: {
    title: 'Gatsby + Prismic Tutorial',
    description: 'Learn how to integrate Prismic into your Gatsby project.',
  },
  plugins: [
    'gatsby-plugin-react-helmet',
    {
      resolve: 'gatsby-plugin-prefetch-google-fonts',
      options: {
        fonts: [
          {
            family: 'Lato',
            variants: ['400', '400i', '700', '700i', '900'],
          },
          {
            family: 'Amiri',
            variants: ['400', '400i', '700', '700i'],
          },
        ],
      },
    },
    'gatsby-transformer-sharp',
    'gatsby-plugin-sharp',
    {
      resolve: 'gatsby-plugin-manifest',
      options: {
        icon: 'src/images/favicon.png',
      },
    },
    {
      resolve: '@prismicio/gatsby-source-prismic-graphql',
      options: {
        repositoryName: 'your-repo-name',
        pages: [{
          type: 'Page',
          match: '/:uid',
          path: '/page-preview',
          component: require.resolve('./src/templates/Page.js'),
        }],
      },
    },
  ],
}

As you can see, we are adding a pages configuration. This will handle any dynamic pages we want to generate from Prismic. Here is a quick explanation of each attribute:

  • type - This is the name of the document type in Prismic that we want to use. In our case we want to generate pages using our "Page" type.
  • match - This is the url structure our generated pages will have. In this case, we want to use the UID value on top of the website root. For example http://localhost:8000/about and http://localhost:8000/more-info where 'about' and 'more-info' are the UID values.
  • path - This is the url we will use when previewing an unpublished page from Prismic. You can ignore this for now. Just know that it is required to make this all work.
  • component - This is the path to the page component in our project that we will use for this page type. We will create this in our next step.

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.

Delete the hardcoded pages

Don't skip this step

If you skip this step, you'll end up with errors in the next step.

Before we actually create the page template we will first need to remove the hardcoded pages from the project. Delete the /src/pages/about.js and /src/pages/more-info.js files.

Create the page template

Inside the src folder in your project files, create a new folder called templates. In this folder, create a new file named Page.js. 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 Layout from '../components/Layout'

const Page = ({ path }) => {
  return (
    <Layout>
      <main className="container">
        <h1>Page: {path}</h1>
      </main>
    </Layout>
  )
}

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 should have been dynamically generated and look like this:

The working pages

Great, our pages are correctly being generated. Now we need to build our query to retrieve the Prismic content and render the content in the page template.

Query the page

If you don't already have your project running, use the npm start command in your terminal to launch your project then head to the Explorer: http://localhost:8000/___graphql.

The query we need will look very similar to the query we had for the homepage. Here's what you need to put into the left-hand panel of your GraphQL Explorer:

  • 1st tab: The query
  • 2nd tab: The query variable
  • GraphQL query
  • Query variables
Copy
query PageQuery($uid: String) {
  prismic {
    allPages(uid: $uid) {
      edges {
        node {
          _meta {
            uid
          }
          body {
            __typename
            ...on PRISMIC_PageBodyText {
              type
              primary {
                columns
                content
              }
            }
            ...on PRISMIC_PageBodyQuote {
              type
              primary {
                quote
              }
            }
            ...on PRISMIC_PageBodyFull_width_image {
              type
              primary {
                full_width_image
                
              }
            }
            ...on PRISMIC_PageBodyImage_gallery {
              type
              primary {
                gallery_title
              }
              fields {
                image
                image_description
                link {
                  _linkType
                  ...on PRISMIC_Page {
                    _meta {
                      type
                      uid
                    }
                  }
                  ...on PRISMIC_Homepage {
                    _meta {
                      type
                    }
                  }
                }
                link_label
              }
            }
            ...on PRISMIC_PageBodyImage_highlight {
              type
              primary {
                featured_image
                title
                description
                link {
                  _linkType
                  ...on PRISMIC_Page {
                    _meta {
                      type
                      uid
                    }
                  }
                  ...on PRISMIC_Homepage {
                    _meta {
                      type
                    }
                  }
                }
                link_label
              }
            }
          }
        }
      }
    }
  }
}
Copy
{
  "uid": "about"
}

You can run the query by pressing the "play" button at the top, which should then show you the results of the query on the right.

The working GraphQL query

So we know that the query is working. There are a few important things to note here:

  • The Page Custom Type is repeatable, so we need a way 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 in your project this is automatically generated during the site build.

Now that we have our query, let's add it to our Page template component.

Update the Page template component

Open your project files and navigate to src/templates/Page.js. One nice thing about the way the content has been modeled is that we can use the same SliceZone component we created in the previous article here as well. Replace the existing code in Page.js with the following.

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 }) => {
  const prismicContent = data.prismic.allPages.edges[0]
  if (!prismicContent) return null
  const document = prismicContent.node

  const capitalizeFirstLetter = (input) => {
    return input[0].toUpperCase() + input.slice(1)
  }

  return (
    <Layout>
      <SEO title={capitalizeFirstLetter(document._meta.uid)} />
      <SliceZone sliceZone={document.body} />
    </Layout>
  )
}

export const query = graphql`
query PageQuery($uid: String) {
  prismic {
    allPages(uid: $uid) {
      edges {
        node {
          _meta {
            uid
          }
          body {
            __typename
            ... on PRISMIC_PageBodyText {
              type
              primary {
                columns
                content
              }
            }
            ... on PRISMIC_PageBodyQuote {
              type
              primary {
                quote
              }
            }
            ... on PRISMIC_PageBodyFull_width_image {
              type
              primary {
                full_width_image
              }
            }
            ... on PRISMIC_PageBodyImage_gallery {
              type
              primary {
                gallery_title
              }
              fields {
                image
                image_description
                link {
                  _linkType
                  ... on PRISMIC_Page {
                    _meta {
                      type
                      uid
                    }
                  }
                  ... on PRISMIC_Homepage {
                    _meta {
                      type
                    }
                  }
                }
                link_label
              }
            }
            ... on PRISMIC_PageBodyImage_highlight {
              type
              primary {
                featured_image
                title
                description
                link {
                  _linkType
                  ... on PRISMIC_Page {
                    _meta {
                      type
                      uid
                    }
                  }
                  ... on PRISMIC_Homepage {
                    _meta {
                      type
                    }
                  }
                }
                link_label
              }
            }
          }
        }
      }
    }
  }
}
`

export default Page

Now when you refresh your site, you should see your page content being displayed correctly. Your repeatable 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 →