How to add automatic Time To Read to Contentful and Gatsby
This quick guide shows you how you can add automatic Time To Read amounts to your Contentful articles that are connected to Gatsby.
The TTR (Time To Read) calculation happens on build time, meaning that it has zero impact on your client-side performance!
As TTR generation happens on build time, you have to utilize the gatsby-node.js
file for it. Add this to the gatsby-node.js
file:
1// Package below is required for calculating blog post length in words2const { documentToPlainTextString } = require("@contentful/rich-text-plain-text-renderer")3// Package below is required for counting the words by turning them into an array4const words = require('lodash/words')5
6// This inserts additional "Time To Read" field into article rich text query7exports.onCreateNode = ({ node, actions }) => {8 const { createNodeField } = actions9 10 const timeToRead = (content) => {11 let TTR;12 // Change the WPM amount (240) below to higher number if your readers are faster13 // or lower if your readers are slower14 const avgWPM = 240;15 const wordCount = words(content).length;16 TTR = Math.round(wordCount / avgWPM);17 if (TTR === 0) {18 TTR = 1;19 }20 return TTR21 }22 23 // Change the "ContentfulBlogArticle" below to match your Content Type24 if (node.internal.type === 'ContentfulBlogArticle') {25 // Match the "bodyContent" below to match the name of your rich text field26 const data = JSON.parse(node.bodyContent.raw);27 const allText = documentToPlainTextString(data);28 createNodeField({ node, name: 'timeToRead', value: timeToRead(allText) })29 }30}
In the example above you need to change ContentfulBlogArticle
to match the content type of your blog posts and bodyContent
to match the name of your article's rich text field. Also if you don't have the@contentful/rich-text-plain-text-renderer
and lodash/words
packages installed for doing the word counting, do npm i @contentful/rich-text-plain-text-renderer lodash/words
to install the necessary packages.
Now you can query the reading time like this (the number is the reading time in minutes):
And you would probably use it like this:
<p>Time to read: ${data.contentfulBlogArticle.fields.timeToRead} minutes</p>
So what does it do exactly? Basically the code adds a new node to be part of the GraphQL query. That node is "timeToRead", which is calculated this way: first rich-text-plain-text-renderer
is used to turn the rich text into plain text. Then lodash/words
is used to turn the plain text into an array of words. That array of words gets counted and then divided by the average words per minute reading ability of an average human. It is around 240, so if you want to go with the average, just keep it at 240. The end result of this is how many minutes it takes to read the whole rich text. The result gets rounded to nearest full digit, so if it happens to be rounded to a zero, we round it up to 1 instead. Now this minute amount is available to be queried via GraphQL.