7

Step to Step Guide on Creating a Blog using Nx Gatsby + WordPress

 2 years ago
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:

1*-yQyRM4-JJz2Z4sI_kmtoA.png?q=20
step-to-step-guide-on-creating-a-blog-using-nx-gatsby-wordpress-ac7e9bfc0efd
WordPress Site 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.

1*QvXOd-tiHrN3c_UDTPsYyg.png?q=20
step-to-step-guide-on-creating-a-blog-using-nx-gatsby-wordpress-ac7e9bfc0efd
Local GraphiQL Tool

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 in gatsby-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.

1*tfHKWagsCjRdG44n39bp7w.png?q=20
step-to-step-guide-on-creating-a-blog-using-nx-gatsby-wordpress-ac7e9bfc0efd

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.

1*lPBb8qAix7eVM8RUP0oqZw.png?q=20
step-to-step-guide-on-creating-a-blog-using-nx-gatsby-wordpress-ac7e9bfc0efd
Create templates 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:

1*3MySqUNbROieVIaaL7k1SA.png?q=20
step-to-step-guide-on-creating-a-blog-using-nx-gatsby-wordpress-ac7e9bfc0efd
Local GraphiQL Tool

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:

1*dqDJpyM0S-YnMG5BfE9pZg.png?q=20
step-to-step-guide-on-creating-a-blog-using-nx-gatsby-wordpress-ac7e9bfc0efd
Serving up the blog-wordpress

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:

1*62m8AFeGXYeccIYQorR_WQ.png?q=20
step-to-step-guide-on-creating-a-blog-using-nx-gatsby-wordpress-ac7e9bfc0efd
ui folder generated

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:

1*KKqtKHh7DpgD2UnLpsSOlQ.png?q=20
step-to-step-guide-on-creating-a-blog-using-nx-gatsby-wordpress-ac7e9bfc0efd
post-summary folder under 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:

1*101eHPZTBTk3f0hSz_5xbQ.png?q=20
step-to-step-guide-on-creating-a-blog-using-nx-gatsby-wordpress-ac7e9bfc0efd
Serve up the blog with material-ui

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.

1*tfHKWagsCjRdG44n39bp7w.png?q=20
step-to-step-guide-on-creating-a-blog-using-nx-gatsby-wordpress-ac7e9bfc0efd
Serving up the app with Pagination

Now you got all of your blog posts displayed nicely with styling and pagination. It is done! Hurray~


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK