In this part we will learn in detail how to use Gatsby to create components for a website and take the data for each component from Wordpress.
The final source code: https://github.com/dinhanhthi/wordpress-gatsby
I do not talk too much about how to make your website like mine. That's something personal! I also do not talk about React syntax (The official document is great enough and it's out of scope for this post!). I am just talking about the techniques and tips I use to build the parts of the site.
Some descriptions are taken directly from the introduction of the projects.
- cntl: If you use a library like Tailwind css where you compose your styles by providing lots of class names this utility tool can help you a lot.
- React Icons: Include popular icons in your React projects easily with react-icons, which utilizes ES6 imports that allows you to include only the icons that your project is using.
Fontello is an icon font generator that you can see as an alternative to Fontawesome. It includes several free icons from various services and allows you to upload your own icons (svg files) and create the appropriate icon fonts for you.
👉 IcoMoon is another wonderful alternative.
1npm install -g fontello-cli
On fontello.com, upload the configuration file from
/src/fontello/config.json
. Add any other icons you want. After making your selection, click "Get config only".Create a shortcut like this in
package.json
1{
2 "scripts": {
3 "ud-fontello": "npx rimraf .fontello-session && fontello-cli --config src/fontello/config.json --css src/fontello/css --font src/fontello/font install"
4 }
5}
If you have any updates, just go to the source folder and run
npm run ud-fontello
!Sometimes, there are duplicates of hex/decimal codes (although the names are different). Navigate to the "Customize Codes" tab on the fontello website, find the duplicates, and change them. Note that, on this tab, the codes are displayed in hexa-base, while in the downlowded configuration they are displayed in decimal-base (
"code"
field). On this site you can convert the two formats.Finally, add the following line to
gatsby-browser.tsx
1import './src/fontello/css/fontello.css'
How to use?
1<i className="icon-right-open"></i>
Suppose you want to create a
Navigation
component for the menu bar (src/components/navigation.tsx
),1import * as React from 'react'
2
3type NavigationOptions = {
4 bgClass?: string
5}
6
7export default function Navigation({ options }: { options?: NavigationOptions }) {
8 return <div>This is the navigation!</div>
9}
In
src/layouts/base.tsx
1import * as React from 'react'
2import Navigation from '../components/navigation'
3
4export default function Base({ children }) {
5 return (
6 <>
7 <Navigation options={{ bgClass: 'bg-white' }} />
8 <main role="main">{children}</main>
9 <Footer />
10 </>
11 )
12}
Use the shortcodes as in the previous section. In this section you will learn how to retrieve menu data from Wordpress and read it into Gatsby.
👉 An example of a navigation bar from my personal blog based on Tailwind (demo).
To get data from WP Menu, on WP head to Appearance > Menus > Create a menu (or choose an existing one).
In Wordpress, taxonomy pages are pages like categories and tags (pages that contain all posts in a category or tag). However, this section is also useful for creating pages like "author".
For example, we will create a page like
/category/math/
that contains a list of posts in the category "Math".To create such a custom page like that, Gatbsy uses
createPage
. Broadly speaking, we proceed as follows,The following codes are examples only, they do not include error checking steps. You will need to add more codes to make sure everything works!
Make the same things for tag and author pages.
The sample codes in the previous section are for creating a full-size category page. In other words, it creates a page that contains all the posts in that category. If you have a site with many posts, you can split the category page into multiple pages, for example,
/category/math/page/1/
.Main idea: in
gatsby-node.ts
, we will not create just one page, but determine how many pages we will create. For each page, we need the index of the post we start with (offset
), the number of posts on that page (postsPerPage
) and finally the uri of the page (/category/math
for the first page and /category/math/page/i
for pages 2, 3, ...).Before modifying the
taxonomy.tsx
file, you need to create a component for the pagination like below,Method 1: Your wordpress site has an About page (
/about/
), you need to create a corresponding file in src/pages/
, i.e. src/pages/about.tsx
. The same for other pages.Method 2: An alternative way to do this automatically is to use
gatsby-node.ts
, as we do with category and tag. In gatsby-node.ts
, we query all pages with their uri and the required data. We use this information to create the appropriate pages. With this method, we do not have to manually create each file for each page in src/pages/
as we do with Method 1.Above codes in
gatsby-node.ts
, we manually ignore the /all/
page with pages.filer(node => node.uri !== '/all/')
. We can do better than that by creating a new field in the WP, say "createDifferent" using ACF and then ignore it in gatsby-node.ts
via the GraphQL query.Let us make the most important part, a post template. This is the one displaying your post content when you browser its URL. The idea is almost the same as in previous sections. We start from
gatsby-node.ts
to get the list of posts with their neccessary information (uri, id, its brother posts' information,...). These informations will be parsed to createPage()
and be coupled with template-post.tsx
to generate the post. Below are the main codes.To apply TailwindCSS to the components of posts (fonts, texts, spacing, tables, links,...), go to section “Styling the post’s components”.
👉 Read this article: "Native Search vs. Jetpack Instant Search in Headless WordPress With Gatsby" by CSS-Tricks, below are the main parts.
You can go to WP admin > GraphiQL IDE and try
1query pageCategory {
2 posts(where: {search: "toán"}) {
3 nodes {
4 title
5 }
6 }
7}
There is no
posts
on Gatsby GraphQL IDE (localhost:8000/___graphql
)!Yes! WPGraphQL offers a way to search the posts by keywords. In order to communicate directly with our WPGraphQL API, we will install Apollo Client; it takes care of requesting and caching the data as well as updating our UI components.
1npm i @apollo/client cross-fetch
Please check Apollo's pricing page to see what the free query volume is (maximum monthly).
If you have linting problems with "posts", you can change the line
GET_RESULTS
like this,1const gqlIgnoreError = gql
2const GET_RESULTS = gqlIgnoreError`
3 query ($searchTerm: String) {
Then go to http://localhost:8000/search/ to test the results.
If you have an input field in the navigation bar (menu bar, as with our website), you want the keywords to be sent to the search page and the results to be displayed there (same behavior as with the normal WP site).
Yes! We need
encodeURI()
to overcome the problem of special characters!By default, the WPGraphQL posts query returns 10 first posts; we need to do more if we want the results paginated into individual pages. Read this post to learn how to do that.
If you want to add popular posts (in a specific time period, based on the number of views), you can use the same method as in section “Make a search page”, except that we query
popularPosts
in the GraphiQL IDE in WP Admin. Like this,1{
2 popularPosts(first: 10) {
3 nodes {
4 id
5 title
6 date
7 }
8 }
9}
However, the default settings for WPGraphQL do not support the
popularPosts
field. You need to add the appropriate codes (on wpgraphqldocs) in the functions.php
file of the WP theme (In WP Admin > Appearance > Theme File Editor > Theme Functions (functions.php)).If the codes from wpgraphqldocs do not work, modify,
1// this line
2'meta_key' => 'wpb_post_views_count',
3// to this one
4'meta_key' => 'views',
This nice article gives us a way to get related posts of a post via GraphQL query. Depending on the changes to Gatsby and WPGraphQL, the codes in this article no longer work. Below you will find my customizations (without explanations).
First, install the WP plugins Yet Another Related Posts Plugin (YARPP), WP REST Cache (optional). After you have installed and activated these plugins, go to YARPP settings and change all the options you want there, just make sure that:
- "Automatically display related content on" is unchecked for all options.
- "Display related posts in REST API?" is checked.
Then add related posts to the post template (look at this section again).
Again, this post does not include any styles from the current version of Math2IT. This section shows you how to use TailwindCSS to style the content of your post.
Install Tailwind's typography plugin and read its documentation. The most important point is to add the
prose
class to the wrapper of the post.And one more thing: If you have some custom plugins installed in your WP site and they create custom classes, like
<div class="custom-class-from-plugin">
, you need to define this class in your theme.I found this wonderful article. You can follow the steps in this article to make "toc" appear in the GraphQL query.
1query MyQuery {
2 allWpPost(limit: 10) {
3 nodes {
4 id
5 title
6 toc
7 }
8 }
9}
You can modify
template-post.tsx
as follows to show the TOC only if the post contains more than 4 headings.1import { get } from 'lodash'
2
3export default function PostTemplate(props: SinglePostProps) {
4 // ... other codes
5 return (
6 <h2 className="text-xl">TOC</h2>
7 {get(post, 'toc.items.length') > 4 && (
8 <ul>
9 {get(post, 'toc.items').map((item: any) => (
10 <li key={item.url}>
11 <a href={item.url}>{item.title}</a>
12 </li>
13 ))}
14 </ul>
15 )}
16 )
17 // ... other codes
18}
Images hosted on WP are handled well by
gatsby-source-wordpress
plugin. You don't have to worry much about this type of images.You can use an external source to serve your images and insert the links into the WP posts, instead of uploading them directly to WP hosting. In this case, how can we ensure that these images are lazyload and responsive? Surinder Bhomra's article is a good reference for dealing with an external image, but with the condition that you need to use a custom component like
LazyloadImage
for each image. This does not work with the links in the WP posts.It's good if we can "parse" the
post.content
and replace all img
tags with the above mentioned LazyloadImage
component. Let's do it this way. Read Surinder's article if you want to understand the basic ideas of creating and using the LazyloadImage
component.Note that I changed his codes to match TypeScript syntax and also to be compatible with imgur's image URLs (I host my images on imgur, while he hosts his on imagekit).
First we need to install the
react-visibility-sensor
plugin.And then, modify the post template,
For a comment system you need "two-way" directions". One direction is to retrieve all comments from the WP database and the other direction is to publish a new comment to the WP database. The former is easy via the GraphQL with the query
allWpComment
or WpComment
(see http://localhost:8000/___graphql), just like WpPost
. The latter is more difficult. In this post, I have not found a solution yet (let me know if you have one).Another option for you is to use comment systems for static websites. You can find a list of comment systems in the Gatsby documentation.
The "incremental build" = every time you update your website (both styles and WP content), the website automatically detects this and rebuilds it. The special thing about this is that the website only rebuilds the parts of the website that have changed.
As far as I know, the only way to deploy the site in the "incremental build" style is to use Gatsby Cloud, which is not free.
If you want a free version of "incremental build", consider Next.JS (another React SSG framework)
One idea for you is to build your site locally and upload the created folder to Github. Then use a service like Netlify or Vercel to freely host your site. I prefer Vercel with more bandwidth and build time for free tiers.
If you want to reduce the size of your WP site and also optimize it, read Wordpress: Cleanup and Optimization tips.