Search code examples
javascriptreactjsgatsbycontentful

Gatsby second layout template


I have a template that i have created, and it is used for pages that display a single product (blog-post.js). Now i need a new kind of pages with their own template (category-post.js), that will display all products in a certain category. I dont know how many categories will ever be, so i need them dynamic (programmatically created).

To do this i think i'm supposed to use the onCreatePage API. The code worked fine before i added onCreatePage function.

I did it by following these docs from www.gatsbyjs.org, on choosing-the-page-layout. I hope i'm on the right track with this at least.

gatsby-node.js, the issue seems to be here:

exports.createPages = ({ graphql, boundActionCreators }) => {
  const { createPage } = boundActionCreators

  return new Promise((resolve, reject) => {
    const blogPost = path.resolve('./src/templates/blog-post.js')        

    resolve(
      graphql(
        `
          {
            allContentfulBlog(limit: 200) {
              edges {
                node {
                  id
                  categories                  
                  slug
                }
              }
            }
          }
        `
      ).then(result => {
        if (result.errors) {
          console.log(result.errors)
          reject(result.errors)
        }

        result.data.allContentfulBlog.edges.forEach(edge => {         
          createPage({
            path: edge.node.slug,
            component: blogPost,
            context: {
              slug: edge.node.slug,
            },
          })
        })
        return
      })
    )
  })
}

exports.onCreatePage = async ({ page, boundActionCreators }) => {
  const { createPage } = boundActionCreators

  return new Promise((resolve, reject) => {
    if (page.path.match(/^\/category-post/)) {
      // I have created `category-post.js` in the `/layouts/` directory
      page.layout = 'category-post'    

      createPage(page)
    }

    resolve()
  })
}

Terminal enter image description here

I can also specify that i'm using Contentful CMS, can this maybe be done somehow with some API from there?

Someone did something similar and wants to help?


Solution

  • to create pages dynamically you still need to use the createPages API. One thing that people miss is that you can have as much GraphQL query as you want. the onCreatePage is unnecessary in this case because you were looking for pages that are not created

    exports.createPages = ({ graphql, boundActionCreators }) => {
      const { createPage } = boundActionCreators
    
      return new Promise((resolve, reject) => {
        const blogPost = path.resolve('./src/templates/blog-post.js')        
        const categoryPost = path.resolve('./src/templates/category-post.js') 
        resolve(
          graphql(
            `
              {
                allContentfulBlog(limit: 200) {
                  edges {
                    node {
                      id
                      categories                  
                      slug
                    }
                  }
                }
                allContentfulCategory(limit: 200) {
                  edges {
                    node {
                      id
                      categories                  
                      slug
                    }
                  }
                }
              }
            `
          ).then(result => {
            if (result.errors) {
              console.log(result.errors)
              reject(result.errors)
            }
            result.data.allContentfulCategory.edges.forEach(edge => {
             createPage({
                path: `categories/${edge.node.slug}`,
                component: categoryPost,
                context: {
                  slug: edge.node.slug,
                },
              })
            })
            result.data.allContentfulBlog.edges.forEach(edge => {         
              createPage({
                path: edge.node.slug,
                component: blogPost,
                context: {
                  slug: edge.node.slug,
                },
              })
            })
            return
          })
        )
      })
    }