I have set up an ACF options page in WordPress called Projects
Inside the Projects options page there is an ACF repeater allowing the user to add multiple Projects.
In Gatsby, I’m using Graphql to query the data for my Projects in two files:
Inside a custom hook, allowing access to the data globally in my Gatsby site
Inside a gatsby-node.js file in order to generate a slug for my template page called project-details.js
Obviously there is no slug in Graphql for this repeater field in the ACF options page. Instead, I’m generating a slug based on a nested Title text field that’s found inside each Project repeater field.
I’m using both the replaceAll() and toLowerCase() methods to create the slug and then making it available as part of my data.
Here’s my custom hook:
export const useProjectsQueryAlt = () => { const data = useStaticQuery(graphql` query ProjectsQueryAlt { wp { projects { projects { allprojects { projectContent projectTitle featuredImage { mediaItemUrl id } projectGallery { caption id mediaItemUrl } } } } } } `) const project = data.wp.projects.projects.allprojects.map(node => { const { projectContent, projectTitle, featuredImage, projectGallery } = node; const title = node.projectTitle; const spacesToHyphen = title.replaceAll(' ', '-'); const slugFromTitle = spacesToHyphen.toLowerCase() return { projectContent, projectTitle, slug: slugFromTitle, featuredImage, projectGallery: projectGallery.map(node => { const { caption, id, mediaItemUrl } = node; return { caption, id, mediaItemUrl } }) } }) return { project } }
Here’s my gatsby-node file:
const path = require('path') exports.createPages = async ({ graphql, actions }) => { const { data } = await graphql(` query Projects { wp { projects { projects { allprojects { projectTitle } } } } } `) data.wp.projects.projects.allprojects.forEach(node => { const title = node.projectTitle; const spacesToHyphen = title.replaceAll(' ', '-'); const slugFromTitle = spacesToHyphen.toLowerCase() actions.createPage({ path: '/projects/' + slugFromTitle, component: path.resolve('./src/templates/project-details.js'), context: { slug: slugFromTitle }, }) }) }
Here’s my template file project-details.js
import React from 'react' function ProjectDetails() { return ( <div> ...my page template content </div> ) } export default ProjectDetails
I now need to find a way to check that the two appended slugs match in my ‘project-details.js’ template file in order to display the relevant project data to the corresponding URL.
Seeing as I’ve generated my slugs on the front end, following the Gatsby Docs for setting up dynamically generate pages doesn’t align with my use case. I was hoping somebody has had experience with this use case and can point me in the right direction.
Advertisement
Answer
The problem in your approach is that you are generating a “fake” slug based on the title
of the project so you can’t use that field to filter any GraphQL node because the field is not present in the project fields. Your best option is using the title
itself or using any autogenerated identifier (id
, if it’s present as a field).
actions.createPage({ path: '/projects/' + slugFromTitle, component: path.resolve('./src/templates/project-details.js'), context: { title }, })
Note: you can omit { title: title }
You can still use the path
of your generated slug, this is a valid approach.
I’m assuming that if the title
is a unique field, the slug
must be too, hence you will be a valid filter.
Now in the project-details.js
:
import React from 'react' function ProjectDetails({ data }) { console.log("my data is", data); return ( <div> ...my page template content </div> ) } export const query = graphql` query($title: String!) { yourACFNode(title: { eq: $title} ) { # your fields } } ` export default ProjectDetails
Of course, tweak the query above to match your ACF node but get the approach.