1

I have encountered a problem while making a personal Gatsby site whereby blog post files are having thier unique folders included in the slug.

For example a file structure of:

data
|
|– blog
   |
   |– blog-1
   |  |
   |  |-blog-1.mdx
   |  |-img.jpg
   |
   |– blog-2
   |  |
   |  |-blog-2.mdx
   |  |-img.jpg
   |
   |– blog-3
   |  |
   |  |-blog-3.mdx
   |  |-img.jpg

Will, for example, produce slugs like this

{
  "data": {
    "allMdx": {
      "edges": [
        {
          "node": {
            "fields": {
              "slug": "/blog-1/blog-1/"
            },
            "frontmatter": {
              "title": "Blog 1",
              "posttype": "blog"
            }
          }
        },
        {
          "node": {
            "fields": {
              "slug": "/blog-2/blog-2/"
            },
            "frontmatter": {
              "title": "Blog 2",
              "posttype": "blog"
            }
          }
        },
        {
          "node": {
            "fields": {
              "slug": "/blog-3/blog-3/"
            },
            "frontmatter": {
              "title": "Blog 3",
              "posttype": "blog"
            }
          }
        },

I expect them to produce a slug like this:

        {
          "node": {
            "fields": {
              "slug": "/blog-1/"
            },
            "frontmatter": {
              "title": "Blog 1",
              "posttype": "blog"
            }
          }
        },

The path to the parent blog folder is included in my gatsby-config like this:

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

And then my gatsby-node folder is set up 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`)
  const portfolioPost = path.resolve(`./src/templates/portfolio-post.js`)
  const journeyPost = path.resolve(`./src/templates/journey-post.js`)

  return graphql(
    `
      {
        allMdx(
          sort: { fields: [frontmatter___date], order: DESC }
          limit: 1000
        ) {
          edges {
            node {
              fields {
                slug
              }
              frontmatter {
                title
                posttype
              }
            }
          }
        }
      }
    `
  ).then(result => {
    if (result.errors) {
      throw result.errors
    }

    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

      if (post.node.frontmatter.posttype == "portfolio") {
        createPage({
          path: `/portfolio${post.node.fields.slug}`,
          component: portfolioPost,
          context: {
            slug: post.node.fields.slug,
            previous,
            next,
          },
        })
      } else if (post.node.frontmatter.posttype == "journey") {
        createPage({
          path: `/journey${post.node.fields.slug}`,
          component: journeyPost,
          context: {
            slug: post.node.fields.slug,
            previous,
            next,
          },
        })
      } else {
        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,
    })
  }
}

Note that the journey and portfolio paths in this file are at this point in time doing exactly the same thing as the blog path. They are set up in exactly the same way and are just split out depending on posttype. Pages are created fine but they are all using the unwanted folder/file.mdx slug.

Neil Morgan
  • 626
  • 4
  • 17

2 Answers2

1

I am sure there is a better way but I was able to solve it by making changes in gatsby-node.js to only take the substring after the last slash (/) in from the file path. If someone knows a better way I will be glad to know that.

Old:

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

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

New:

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

  if (node.internal.type === `MarkdownRemark`) {
    const value = createFilePath({ node, getNode, trailingSlash:false })
    createNodeField({
      name: `slug`,
      node,
      value: `${value.indexOf("/") > -1 ? value.substring(value.lastIndexOf("/")) : value}`,
    })
  }
}
0

Fixed by looking at other blog examples.

Post filename needs to be index.md or index.mdx

Neil Morgan
  • 626
  • 4
  • 17