Recipes › Reading time with a hook
Introduction
Content
Using content
Plugins
Recipes
Docs/Recipes/Reading time with a hook
Reading time with a hook
What you'll build
A "minutes to read" number that the CMS computes on every save and editors can see but not change. Uses: hooks, field access.
1. The field
{
name: 'readingTime',
type: 'number',
label: { en: 'Reading time (min)', th: 'เวลาอ่าน (นาที)' },
position: 'sidebar',
// Read-only in the admin and the API; the hook below sets it.
access: { update: () => false },
}Field access only filters what people send; hooks can still set the value.
2. The hook
npm install @easy-cms/richtextpnpm add @easy-cms/richtextyarn add @easy-cms/richtextbun add @easy-cms/richtextimport { richTextToPlainText } from '@easy-cms/richtext'
const WORDS_PER_MINUTE = 200
function minutes(body: unknown): number {
const words = richTextToPlainText(body as never).split(/\s+/).filter(Boolean).length
return Math.max(1, Math.round(words / WORDS_PER_MINUTE))
}
// In the posts collection:
hooks: {
beforeChange: [
({ data }) => (data.body === undefined ? data : { ...data, readingTime: minutes(data.body) }),
],
},On an update that doesn't touch body, data.body is missing and the old value stays.
Thai text
Thai has no spaces between words, so counting words by spaces undercounts. Count characters
instead, roughly 800–1,000 per minute for Thai:
Math.round(richTextToPlainText(body).length / 900).
3. Fill existing posts
The hook runs on save. To fill posts that already exist, save each once:
const cms = await getEasyCMS(config) // or useEasyCMS() in Nuxt
const { docs } = await cms.find('posts', { limit: 0, draft: true, depth: 0 })
for (const post of docs) await cms.update('posts', post.id, { body: post.body })Edit this page on GitHubEasy CMS v0.47