question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

How can I make two or more page type creations in 'gatsby-node'?

See original GitHub issue

I have two different content categories, both written in mdx files, that need different routes and templates when being created programmatically. It seems that I can only have one createPages and one createNode in the gatsby-node file, so I am unsure as to how to go about making pages for two or more different content categories that require different routes and frontmatter, content, etc…

Here is some example code, using regex to filter for each query:

const path = require(`path`)

exports.createPages = async ({ graphql, actions }) => {
  const { createPage } = actions 
  const result = await graphql(`
    query {
      articles: allMdx(filter: { fileAbsolutePath: { regex: "/content/words/" } }) {
        edges {
          node {
            id
            fields {
              slug
            }
          }
        }
      }
    }
  `).then(res => res.data )

  result.articles.edges.forEach(({ node }) => {
    createPage({
      path: node.fields.slug,
      component: path.resolve(`./src/templates/article.js`),
      context: {
        slug: node.fields.slug,
        id: node.id
      },
    })
  })
}

exports.createPages = async ({ graphql, actions }) => {
  const { createPage } = actions 
  const result = await graphql(`
    query {
      articles: allMdx(filter: { fileAbsolutePath: { regex: "/content/words/" } }) {
        edges {
          node {
            id
            fields {
              slug
            }
          }
        }
      }
    }
  `).then(res => res.data )

  result.articles.edges.forEach(({ node }) => {
    createPage({
      path: node.fields.slug,
      component: path.resolve(`./src/templates/article.js`),
      context: {
        slug: node.fields.slug,
        id: node.id
      },
    })
  })
}

…but this does not work, as I can only have one createPages in the gatsby-node file. This is the same for node creation, of which I would need two different ones, but I am unsure how to go about this issue either:

const { createFilePath } = require(`gatsby-source-filesystem`)

exports.onCreateNode = ({ node, actions, getNode }) => {
  const { createNodeField } = actions
  if (node.internal.type === `Mdx`) {
    const value = createFilePath({ node, getNode })
    createNodeField({
      name: `slug`,
      node,
      value: `/words${value}`,
    })
  }
}

exports.onCreateNode = ({ node, actions, getNode }) => {
  const { createNodeField } = actions
  if (node.internal.type === `Mdx`) {
    const value = createFilePath({ node, getNode })
    createNodeField({
      name: `slug`,
      node,
      value: `/music${value}`,
    })
  }
}

So basically I do not know how to go about programmatically creating pages for two or more categories of content that each require different graphql queries and templates. I am assuming that I need to combine them under one function, I just don’t know how to go about doing that.

Thank you in advance for any assistance that you may be able to give me 😃

Issue Analytics

  • State:closed
  • Created 4 years ago
  • Comments:13 (6 by maintainers)

github_iconTop GitHub Comments

6reactions
TylerBarnescommented, Dec 17, 2019

Hey @rchrdnsh, You can achieve what you’re looking for by grouping your API code into one function for each node API.

For ex:

const path = require(`path`)

exports.createPages = async ({ graphql, actions }) => {
  const { createPage } = actions 
  const words = await graphql(`
    query {
      articles: allMdx(filter: { fileAbsolutePath: { regex: "/content/words/" } }) {
        edges {
          node {
            id
            fields {
              slug
            }
          }
        }
      }
    }
  `).then(res => res.data )

  words.articles.edges.forEach(({ node }) => {
		createPage({
			path: node.fields.slug,
			component: path.resolve(`./src/templates/article.js`),
			context: {
				slug: node.fields.slug,
				id: node.id,
			},
		})
  })

  const otherContent = await graphql(`
		query {
			articles: allMdx(
				filter: { fileAbsolutePath: { regex: "/content/some-other-content/" } }
			) {
				edges {
					node {
						id
						fields {
							slug
						}
					}
				}
			}
		}
  `).then(res => res.data)

  otherContent.articles.edges.forEach(({ node }) => {
		createPage({
			path: node.fields.slug,
			component: path.resolve(`./src/templates/other-template.js`),
			context: {
				slug: node.fields.slug,
				id: node.id,
			},
		})
  })
}

There are ways to make the code more concise, but for now, try building the query for each in Graphiql, and then console.log() the responses to figure out how to write your logic.

and for onCreateNode you can do something like this:

const { createFilePath } = require(`gatsby-source-filesystem`)

exports.onCreateNode = ({ node, actions, getNode }) => {
	const { createNodeField } = actions
	const value = createFilePath({ node, getNode })
	if (node.internal.type === `Mdx`) {
		createNodeField({
			name: `slug`,
			node,
			value: `/words${value}`,
		})
	} else if (node.internal.type === `SomethingElse`) {
		createNodeField({
			name: `slug`,
			node,
			value: `/music${value}`,
		})
	}
}

What you query and how you create your pages and node fields will be different depending on the requirements of your project, but the code above should give you a general idea of where to start. console.log and graphiql will be your best friends in figuring out how to write your logic. Let me know if you need any more help!

1reaction
TylerBarnescommented, Dec 18, 2019

@rchrdnsh I think the reason that was throwing an error is that createFilePath is meant to be used on file nodes but when it’s outside your conditional it’s being run on every node in your site. Glad you got it working though!

Read more comments on GitHub >

github_iconTop Results From Across the Web

Creating and Modifying Pages - Gatsby
Gatsby makes it easy to programmatically control your pages. Pages can be created in three ways: By creating React components in the src/pages...
Read more >
Gatsby JS Course: How to Create Pages Programmatically
Write the code to create paginated pages and single pages in Gatsby Node and how to pass context to Gatsby templates.This is a...
Read more >
How to create multiple page types dynamically in Gatsby-node.js
You need to refactor your approach, assigning one variable for each query result, one for entries ( result1 ) and one for locations ......
Read more >
How to create pages dynamically in Gatsby
In gatsby-node.js we export createPages API and pass it 2 arguments, graphql for finding the files and actions where createPage is a property...
Read more >
How to generate pages by createPages API with Gatsby.js
Basically, what we need to do is to add a template file: templates/page.js as well as change our gatsby-node.js . Let's start by...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found