Neil
Neil

Reputation: 656

Gatsby - Split out Projects content from Blog content

Context

I have a Gatsby project which contains a working blog section at /blog/
(src/pages/blog.js)

The project builds individual pages for each blog post based on content found in the directory content/blog/post1.mdx for example.

All post are mapped to /blog/ using the results of a graphQL query for a central blog feed.
Seen below:

//src/pages/blog.js
class Blog extends React.Component {
  render() {
    const { data } = this.props
    const siteTitle = data.site.siteMetadata.title
    const posts = data.allMdx.edges

    return (
      <Layout location={this.props.location} title={siteTitle}>
        <SEO title="Blog" />
        <Section>
          <div className="row">
            <div className="col">
              <h1>Blog page</h1>

              <div>
                {posts.map(({ node }) => {
                  const title = node.frontmatter.title || node.fields.slug
                  return (
                    <div key={node.fields.slug}>
                      <h3>
                        <Link to={`blog${node.fields.slug}`}>{title}</Link>
                      </h3>
                      <small>{node.frontmatter.date}</small>
                      <p
                        dangerouslySetInnerHTML={{
                          __html: node.frontmatter.description || node.excerpt,
                        }}
                      />
                    </div>
                  )
                })}
              </div>
            </div>
          </div>
        </Section>
      </Layout>
    )
  }
}

export default Blog

export const pageQuery = graphql`
  query {
    site {
      siteMetadata {
        title
      }
    }
    allMdx(sort: { fields: [frontmatter___date], order: DESC }) {
      edges {
        node {
          excerpt
          fields {
            slug
          }
          frontmatter {
            date(formatString: "MMMM DD, YYYY")
            title
            description
          }
        }
      }
    }
  }
`


This currently is setup with a gatsby-config.js which uses

    {
      resolve: `gatsby-source-filesystem`,
      options: {
        path: `${__dirname}/content/blog`,
        name: `blog`,
      },
    },

...and a gatsby-node.js document which looks like this

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

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

  const blogPost = path.resolve(`./src/templates/blog-post.js`)
  return graphql(
    `
      {
        allMdx(
          sort: { fields: [frontmatter___date], order: DESC }
          limit: 1000
        ) {
          edges {
            node {
              fields {
                slug
              }
              frontmatter {
                title
              }
            }
          }
        }
      }
    `
  ).then(result => {
    if (result.errors) {
      throw result.errors
    }

    // Create blog posts pages.
    const posts = result.data.allMdx.edges

    posts.forEach((post, index) => {
      const previous = index === posts.length - 1 ? null : posts[index + 1].node
      const next = index === 0 ? null : posts[index - 1].node

      createPage({
        path: `blog${post.node.fields.slug}`,
        component: blogPost,
        context: {
          slug: post.node.fields.slug,
          previous,
          next,
        },
      })
    })

    return null
  })
}

exports.onCreateNode = ({ node, actions, getNode }) => {
  const { createNodeField } = actions

  if (node.internal.type === `Mdx`) {
    const value = createFilePath({ node, getNode })
    createNodeField({
      name: `slug`,
      node,
      value,
    })
  }
}


Task

I would like to split out a similar setup but for Project posts at /projects/ instead.

Currently I have added a directory for projects at content/project/project1.mdx
And added the below in gatsby-config.js

    {
      resolve: `gatsby-source-filesystem`,
      options: {
        path: `${__dirname}/content/project`,
        name: `project`,
      },
    },

I am stumbling when it comes to modifying gatsby-node.js to accomodate the new content type and this is where I mainly need help.

I'll then ofcourse need to edit src/pages/blog.js and make a src/pages/projects.js to query and map the same way the blog page does but I have't got that far yet.

Upvotes: 1

Views: 320

Answers (1)

ksav
ksav

Reputation: 20821

In gatsby-node you are currently querying allMdx no matter where they are found.

{
  allMarkdownRemark {
    edges {
      node {
        frontmatter {
          title
        }
      }
    }
  }
}

But you can filter these depending on where they are found using fileAbsolutePath (matching either 'blog' or 'projects' in the pathname)

{
  allMarkdownRemark(filter: {fileAbsolutePath: {regex: "/blog/"}}) {
    edges {
      node {
        frontmatter {
          title
        }
      }
    }
  }
}

You can even combine the queries for both, and alias them to something that makes sense to you.

query myQuery {
  allMyBlogPosts: allMarkdownRemark(filter: {fileAbsolutePath: {regex: "/blog/"}}) {
    edges {
      node {
        frontmatter {
          title
        }
      }
    }
  }
  allMyProjectPosts: allMarkdownRemark(filter: {fileAbsolutePath: {regex: "/projects/"}}) {
    edges {
      node {
        frontmatter {
          title
        }
      }
    }
  }
}

Then you just repeat the same process of looping through the results and using the createPage api to create a page for each (most likely using a new template you have created like blog-post.js)

As always, the graphiql explorer is a great place to explore your schema and experiment with building these queries before taking them into code.

Upvotes: 1

Related Questions