In this article, we are creating a Gatsby and WordPress post detail page with GraphQL and WordPress API to fetch data for WordPress posts.
This blog is a continuation of our previous article, where we explained everything about setting up the Gatsby framework, and we created a page where we displayed all the posts, pages, and category titles and names.
If you are new to Gatsby, then I would suggest you read that article and then come to this article to continue our Gatsby and WordPress API integration series.
Here is the link to the first article of this Gatsby and WordPress Series.
Building a Powerful Blog: Mastering the Art of Gatsby and WordPress Integration
Let’s Start Building are page to display WordPress API responses for a single post based on its URL with Gatsby and GraphQL.
In the previous article we mentioned above, we updated a file index.js to show the list of posts, pages, and categories; I added a link to post titles so that we can click on them and open our single post file to see the post data coming based on its URL.
Index.js file Changes for Gatsby and WordPress post detail
Here is the updated index.js file
import * as React from "react";
import {Link, graphql} from 'gatsby';
const IndexPage = ({data}) => {
const categories = data.allWpCategory.edges;
const pages = data.allWpPage.nodes;
const posts = data.allWpPost.edges;
console.log("alldata",data)
return (
<>
<div class="container">
<h1>Home Page</h1>
<h2>Category List</h2>
<ul>
{categories.map(list=>(
<li>{list.node.name}</li>
))}
</ul>
<h2>Pages List</h2>
<ul>
{pages.map(list=>(
<li>{list.title}</li>
))}
</ul>
<h2>Posts List</h2>
<ul>
{posts.map(list=>(
<li>
<Link to={list.node.slug}>
{list.node.title}
</Link>
</li>
))}
</ul>
</div>
</>
)
}
export default IndexPage;
export const query = graphql`
query {
allWpPost{
edges {
node {
id
title
excerpt
slug
featuredImage {
node {
sourceUrl
}
}
}
}
}
allWpCategory {
edges {
node {
id
name
slug
}
}
}
allWpPage {
nodes {
id
title
uri
}
}
}
`;
Let’s create our singlePost.js file inside the templates folder, which will receive a URI parameter that will be a slug of a WordPress post.
singlePost.js file Changes for Gatsby and WordPress post detail
Below you can see our singlePost.js file, which is similar to our index.js file.
import React from "react";
import { graphql } from "gatsby";
const SinglePost=({data})=>{
const post = data.wpPost;
return (
<>
<h1>
{post.title}
</h1>
<p>
{post.excerpt}
</p>
</>
)
}
export default SinglePost;
export const query = graphql`
query($id: String!) {
wpPost(id: { eq: $id }) {
title
content
excerpt
featuredImage {
node {
sourceUrl
}
}
}
allWpPost(sort: { fields: [date], order: DESC }) {
edges {
node {
id
title
excerpt
slug
featuredImage {
node {
sourceUrl
}
}
}
}
}
}
`;
Similar to the index.js file singlePost.js file has a GraphQL query that gets post data based on the URI, and we have a data variable passing inside the SinglePage function that has all the data results, getting from the GraphQL query.
If you can see this part from the above code, then you can see that there is one other wpPost query that is taking an id, then you can guess that this is for fetching the data for a single post based on its id, this id can be a post id or a URI.
wpPost(id: { eq: $id }) {
title
content
excerpt
featuredImage {
node {
sourceUrl
}
}
}
Let me show you the output for the above code of the singlePost.js file, but remember your code will not work till the above changes, there is one more file that you need to update.
gatsby-node.js file Changes for Gatsby and WordPress post detail
Now we need to update that file which is the gatsby-node.js file. Here is the updated file.
/**
* Implement Gatsby's Node APIs in this file.
*
* See: https://www.gatsbyjs.com/docs/reference/config-files/gatsby-node/
*/
/**
* @type {import('gatsby').GatsbyNode['createPages']}
*/
exports.createPages = async ({ graphql,actions }) => {
const { createPage } = actions
const result = await graphql(`
query {
allWpPost {
edges {
node {
id
slug
}
}
}
}
`);
const posts = result.data.allWpPost.edges;
posts.forEach(({ node }) => {
createPage({
path: node.slug,
component: require.resolve("./src/templates/singlePost.js"),
context: {
id: node.id,
},
});
});
/*Below code is default page for gatsby project so ignore it for now */
createPage({
path: "/using-dsg",
component: require.resolve("./src/templates/using-dsg.js"),
context: {},
defer: true,
})
}
So let me explain to you how this file works, and how this create page function is creating static pages during the development process.
So in the below code, we have a create pages function that has actions and garphql, graphql is for executing GarphQL queries and actions have a property called createPage, which basically creates pages dynamically according to the data returned in query results.
exports.createPages = async ({ graphql,actions }) => {
const { createPage } = actions
const result = await graphql(`
query {
allWpPost {
edges {
node {
id
slug
}
}
}
}
`);
Now let’s check this createPage function.
const posts = result.data.allWpPost.edges;
posts.forEach(({ node }) => {
createPage({
path: node.slug,
component: require.resolve("./src/templates/singlePost.js"),
context: {
id: node.id,
},
});
});
So before the createPage function, we are getting GraphQL query data inside the variable posts and we are applying a forEach loop on this posts variable during this forEach, we are creating static files for each post.
Inside createPage we have a path which is basically a URL path structure, so with this path, we can understand that this post details page will open at a location https://localhost:8000/single-post-uri, Here node.slug is a post-URI.
component inside createPage is basically a file location, which file data should show when this path executes.
Now the last one is the id, which is basically a post id and is defined inside a context, which can be accessed by the GraphQL query we defined inside the singlePost.js page.
Now, let’s see the output for all these files changes inside the Index.js, singlePost.js, and gatsby-node.js
First, we will the index.js file because its the root file and will be executed first whenever we open the https://localhost:8000/
Now click on any of the posts and this will open the singlePost.js file data.
So, now you have the idea of how you can create a Gatsby and WordPress post detail page using GraphQL API.
You can see that the post content has some HTML syntax, to remove these and sanitize this content you can use dangerouslySetInnerHTML inside your div element.
return (
<>
<h1>
{post.title}
</h1>
<div dangerouslySetInnerHTML={{ __html: post.content }}></div>
</>
)
}
Now the output will look more accurate and clean. Also instead of excerpt it change it to content which has all the data of post.
In our next article, we will display all the tags of a single post and will create a page that shows all the results base on the tag clicked on the post details page.