patrick
patrick

Reputation: 353

Gatsby + Contentful URL Structure Problems

I'm having trouble setting up the proper URL structure using Gatsby + Contentful.

My folder structure looks like this:

├── src
├── pages
├──── Learn (folder)
│    ├── index.js (contentful learn-template queries all pages)
│    ├── guides (folder)
├────└────
├─────────├── index.js (contentful guide-template queries all guides)

I'm using gatsby-node.js to query my contentful pages with createPages:

const path = require('path')

exports.createPages = async ({ graphql, actions }) => {
    const { createPage } = actions
    const result = await graphql(`
  query GetContent {
page: allContentfulPages(filter: {node_locale: {eq: "en-US"}}) {
    nodes {
      slug
    }
  }
guides: allContentfulGuides(filter: {node_locale: {eq: "en-US"}}) {
    nodes {
      slug
    }
  }
}
  `)

    result.data.page.nodes.forEach(page => {
        createPage({
            path: `${page.slug}`,
            component: path.resolve(`src/pages/guides/index.js`),
            context: {
                slug: page.slug
            },
        })
    })

    result.data.guides.nodes.forEach(guides => {
        createPage({
            path: `${guides.slug}`,
            component: path.resolve(`src/pages/guides/index.js`),
            context: {
                slug: guides.slug
            },
        })
    })
}

The problem that I'm having is that the URL looks like that:

http://localhost:8000/learn/{contenfulGuides}/

But I want to achieve this:

http://localhost:8000/{contentfulPages}/{contentfulGuides}/

I've looked everywhere but haven't found topics about this.

I want to know how to remove the folder name in the URL and instead paste the contentful page slug.

Hope someone can help sending me in the right direction.

EDIT:

I think some people don't understand what I meant so I'll explain it a bit more simply here.

I have 2 contentful models, contentfulPages and contentfulSubPages. Each of them holds multiply pages and sub-pages. Now, if I use a template folder and the gatsby-node.js from above the URL's looking like that:

http://localhost:8000/{contentfulPages}/ http://localhost:8000/{contentfulSubPages}/

Two separated URLs. But I want to achieve this:

http://localhost:8000/{contentfulPages/contentfulSubPages}/

Upvotes: 0

Views: 565

Answers (2)

Ferran Buireu
Ferran Buireu

Reputation: 29320

To resolve the issue it's preferable to use the standard way of creating pages in Gatsby, using the gatsby-node.js which gives you more flexibility to manipulate the code.

Since your contentfulPage is linked to contentfulSubPages (one-to-many relationship), you can create nested routes using nested loops as the result of your GraphQL query. Something like:

const path = require('path')

exports.createPages = async ({ graphql, actions }) => {
    const { createPage } = actions
    const result = await graphql(`
    query GetContent {
     pages: allContentfulPages(filter: {node_locale: {eq: "en-US"}}) {
       nodes {
         slug
         allGuides{
           slug
         }
       }
     }
   }
  `)

    result.data.pages.nodes.forEach(page => {
        createPage({
            path: `${page.slug}`,
            component: path.resolve(`src/templates/page-template.js`),
            context: {
                slug: page.slug
            },
        })
      if(page.allGuides){
         page.allGuides.forEach(guide =>{
            createPage({
            path: `${page.slug}/${guide.slug}`,
            component: path.resolve(`src/templates/guide-template.js`),
            context: {
                slug: guide.slug
            },
        })}
      }
    })
}

Note: this is an approximation, you may need to change a little bit as well as the query and the properties of the GraphQL nodes.

First of all, you need to loop through allContentfulPages (aliased as pages) and create a page for each node. Once done that, you can check if that page has subpages, allGuides in this case, and make a nested loop to create a nested path (path: `${page.slug}/${guide.slug}` ).

You can extrapolate the same approach for all your content models.

Upvotes: 1

coreyward
coreyward

Reputation: 80041

Files under pages are treated as 1:1 with your output. That is, a file at src/pages/about.js(x) will produce a page at /about when you run a build.

When you want to generate pages with dynamic paths, it's better to put the template files in a templates folder, such as src/templates/guide.js and provide that path to the createPage call in gatsby-node.js. The output slug will then match the path parameter you pass to createPage.

Upvotes: 1

Related Questions