Reputation: 353
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
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
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