Step to Step Guide on Creating a Blog using Nx Gatsby + WordPress
source link: https://blog.nrwl.io/step-to-step-guide-on-creating-a-blog-using-nx-gatsby-wordpress-ac7e9bfc0efd
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
Sourcing from WordPress
To source blog posts from WordPress, you need to install gatsby-source-wordpress plugin:
# npm
npm install gatsby-source-wordpress --save# yarn
yarn add gatsby-source-wordpress
In the gatsby-config.js
file, add gatsby-source-wordpress plugin:
module.exports = {
...
plugins: [
...
{
resolve: `gatsby-source-wordpress`,
options: {
url: `< your Wordpress blog site >/graphql`,
},
},
],
};
Also in your WordPress blog settings, you need to add WPGraphQL and WPGatsby plugins:
If you serve up your app locally usingnpm run start
or yarn start
, at http://localhost:4200/___graphql
, you would notice that you now have queries with wp
in the name. You can play around with it to construct the query that you want.
Create Pages
There are 2 ways to create pages in Gatsby:
- Add a file directly under
src/pages
folder to create a static page - Use
createPages
function ingatsby-node.js
to generate dynamic pages
In this example, you will try to create a list of blogs as shown below with code inspired by the repo Gatsby WordPress blog starter.
Since the data source is dynamic, you need to use createPages
function to generate the page. In the future, if more blog posts are added to the WordPress source, createPages
function will handle those changes.
Create Pages in Gatsby Node
In apps/blog-wordpress/gatsby-node.js
, you need to add the function createPages
. Inside this function, an action called createPage
is passed in. The below code will create a route path /blogs
using the template at ./src/templates/blog-post-archive/blog-post-archive.tsx
.
const path = require(`path`);exports.createPages = async (gatsbyUtilities) => {
await gatsbyUtilities.actions.createPage({
path: `/blogs`,
component: path.resolve(
`./src/templates/blog-post-archive/blog-post-archive.tsx`
),
});
};
Create Templates
Now you need to create a page template to be used for createPages
. Under src/templates
folder, create a component called blog-post-archive
.
In this template file, to query data from WordPress, you need to add a page query:
import { graphql } from 'gatsby';export const pageQuery = graphql`
// query goes here
`;
In this example, it is going to query id, title, and excerpt from all the WordPress posts sorted by date in descending order:
export const pageQuery = graphql`
query WordPressPostArchive {
allWpPost(sort: { fields: [date], order: DESC }) {
nodes {
id
title
excerpt
}
}
}
`;
You could see the result of this query at http://localhost:4200/___graphql
:
The result from this query will be passed to the data prop of this component:
export interface BlogPostArchiveProps {
data: {
allWpPost: {
nodes: {
id: string;
title: string;
excerpt: string;
}[];
};
};
}
blog-post-archive.tsx
will look like below:
Notice for title and excerpt in WordPress query result, it will sometimes return HTML code in the string. You need to add a library html-react-parser to parse the HTML code to display them correctly:
# npm
npm install html-react-parser --save# yarn
yarn add html-react-parser
In blog-post-archive.tsx
, it will become:
import parse from 'html-react-parser';<h2>{parse(post.title)}</h2>
<div>{parse(post.excerpt)}</div>
Now if you serve up the app using nx serve blog-wordpress
, go to http://localhost:4200/blogs, it should show a list of blogs:
Great! So now you have created the first page to showcase all your blogs. However, this page does not have any styling.
For each blog post, you now need to create a shared UI component to display the preview content. The UI library that we create here will be presentational and will receive all of the data from the page, it is similar to Gatsby components.
Create Shared UI Library
To create a React library, run:
npx nx generate lib ui
You will then receive these prompts in your command line:
✔ Which stylesheet format would you like to use? · none
This should create a ui
folder under libs:
Create a UI component for Blog Summary
Now run the below code to create a component under ui
library:
nx generate @nrwl/react:component post-summary -—project=ui --export
It should generate post-summary
folder under libs/ui/src/lib
:
libs/ui/src/lib
In post-summary.tsx
, add below code to show the post title and excerpt:
Go back the the blog-post-archive.tsx
template, change the file to use the PostSummary
component under ui
library:
import { PostSummary } from '@nx-gatsby-blogs/ui';export function BlogPostArchive({ data }: BlogPostArchiveProps) {
return data.allWpPost.nodes.map((post) => (
<PostSummary key={post.id} post={post} />
));
}
Serve up the app using nx serve blog-wordpress
and it should still work the same as before.
Add Data Transform Function
To display more data, in blog-post-archive.tsx
template, add more keys to the query:
export const pageQuery = graphql`
query WordPressPostArchive {
allWpPost(sort: { fields: [date], order: DESC }) {
nodes {
id
excerpt
date(formatString: "MMMM DD, YYYY")
title
uri
featuredImage {
node {
altText
localFile {
url
}
}
}
}
}
}
`;
So the data resulting from the above query will have the below interface:
export interface BlogPostArchivePropsData {
allWpPost: {
nodes: {
id: string;
title: string;
excerpt: string;
date: string;
uri: string;
featuredImage?: {
node: {
altText: string;
localFile: {
url: string;
};
};
};
}[];
};
}
The blog-post-archive
’s component props will become:
export interface BlogPostArchiveProps {
data: BlogPostArchivePropsData;
}
Now you are getting more data from the WordPress GraphQL query in the blog-post-archive
template, and you need to pass down this data down to the post-summary
component for display. However, you need to decouple the query result data structure from the data we pass to the post-summary
component.
Under libs/ui/src/models
, add this interface that defines the data to be passed to PostSummary:
export interface BlogPost {
id: string;
title: string;
excerpt: string;
date: string; // date in format of MMMM DD, YYYY
url: string;
content?: string;
featuredImage: {
src: string;
alt: string;
};
}
So the PostsSummary’s component props will become:
import { BlogPost } from '../../models/blog-post';export interface PostSummaryProps {
post: BlogPost;
}
Now you need to add a function that transforms data from the interface BlogPostArchivePropsData
to interface BlogPost
.
export function transformBlogPostArchivePropsDataToBlogPosts(
data: BlogPostArchivePropsData
): BlogPost[] {
return data?.allWpPost?.nodes?.map((post) => ({
id: post.id,
title: post.title,
excerpt: post.excerpt,
date: post.date,
url: post.uri,
featuredImage: post.featuredImage && {
src: post.featuredImage.node?.localFile?.url,
alt: post.featuredImage.node?.altText,
},
}));
}
Now in blog-post-archive.tsx
template, use this data transform function before passing the posts to PostSummary:
export function BlogPostArchive({ data }: BlogPostArchiveProps) {
const posts: BlogPost[] = transformBlogPostArchivePropsDataToBlogPosts(data); return posts.map((post) => <PostSummary key={post.id} post={post} />);
}
Now you have decoupled the WordPress GraphQL query result to the data used in the components. In the future, if the schema of WPGraphQL changes or you want to reuse PostSummary to display other things, it would be easy to do so.
Add material-ui
This example uses material-ui as its styling and component library. To install material-ui:
# npm
npm install --save @material-ui/core @material-ui/lab gatsby-plugin-material-ui# yarn
yarn add @material-ui/core @material-ui/lab gatsby-plugin-material-ui
In gatsby-config.js, add the gatsby-plugin-material-ui:
module.exports = {
...
plugins: [
...
gatsby-plugin-material-ui,
],
};
Now in the post-summary.tsx
, you can now use components from material-ui. The below example uses the Card component to display the blog posts:
Also in blog-post-archive.tsx
, we could use the layout from material-ui as well. The below example uses Grid to display the blog list (the entire file will look like this):
<Grid container spacing={5}>
{posts.map((post) => {
return (
<Grid item xs={12} sm={6} md={4} key={post.id}>
<PostSummary post={post}></PostSummary>
</Grid>
);
})}
</Grid>
Now if you serve up the app, it will look like this:
Awesome! You now have a styled page that displays ALL your blogs. However, if you have too many blogs that do not fix well on one page, you need to add pagination.
Add Pagination
For pagination, you would need to know exactly how many pages you would need when you create pages because you could not change your GraphQL query at runtime.
“Gatsby uses GraphQL at build-time and not for live sites.” — Gatsby Docs
In gatsby-node.js
, you need to change the createPage
function to:
- Get the count of all blog posts
- Figure out how many pages you would need
- For each page, generate a page at
/blogs/<current page number>
Below code is inspired by Gatsby WordPress blog starter:
For createPage
the function above, you will notice that there are additional keys that got passed to context. These keys are passed to pageContext props to blog-post-archive.tsx
and GraphQL query:
export interface BlogPostArchiveProps {
data: BlogPostArchivePropsData;
pageContext: {
offset: number;
postsPerPage: number;
currentPageNumber: number;
totalPageCount: number;
};
}export const pageQuery = graphql`
query WordPressPostArchive($offset: Int!, $postsPerPage: Int!) {
allWpPost(
sort: { fields: [date], order: DESC }
limit: $postsPerPage
skip: $offset
)
So now you could add the Pagination component to blog-post-archive.tsx
(entire file will look like this):
{pageContext.totalPageCount > 1 && (
<Box display="flex" justifyContent="center" m={2}>
<Pagination
color="primary"
page={pageContext.currentPageNumber}
count={pageContext.totalPageCount}
renderItem={(item) => (
<PaginationItem
component={Link}
to={`/blogs/${item.page}`}
{...item}
/>
)}
/>
</Box>
)}
So now if you serve up the app, you should see the first page at http://localhost:4200/blogs/1 with pagination on the bottom.
Now you got all of your blog posts displayed nicely with styling and pagination. It is done! Hurray~
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK