Skip to main content

Blog Plugin Configuration

Complete guide to configuring the Docusaurus blog plugin for optimal blogging experience.

Overview

The @docusaurus/plugin-content-blog plugin provides the blog feature for Docusaurus. When using @docusaurus/preset-classic, the blog plugin is included by default and can be configured through preset options.

Current Configuration

Our blog is configured in docusaurus.config.ts with the following settings:

blog: {
blogTitle: 'Pacing Agency Blog',
blogDescription: 'Digital marketing insights, tech stack tips, and industry expertise from Pacing Agency.',
blogSidebarTitle: 'Recent posts',
blogSidebarCount: 10,
postsPerPage: 10,
showReadingTime: true,
feedOptions: {
type: ['rss', 'atom'],
xslt: true,
title: 'Pacing Agency Blog',
description: 'Digital marketing insights, tech stack tips, and industry expertise from Pacing Agency.',
copyright: `Copyright © ${new Date().getFullYear()} Pacing Agency`,
},
editUrl: 'https://github.com/Pacing-Agency/techstackdocs/tree/main/docusaurus/',
onInlineTags: 'warn',
onInlineAuthors: 'warn',
onUntruncatedBlogPosts: 'warn',
}

Key Configuration Options

Basic Settings

OptionValueDescription
blogTitle'Pacing Agency Blog'Blog page title for SEO
blogDescriptionMarketing insights...Meta description for SEO
routeBasePath'blog' (default)URL route for blog section
postsPerPage10Number of posts per listing page
showReadingTimetrueShow estimated reading time
OptionValueDescription
blogSidebarTitle'Recent posts'Title of blog sidebar
blogSidebarCount10Number of posts to show in sidebar

Options: Use 'ALL' to show all posts, or 0 to disable the sidebar entirely.

Feed Configuration

RSS and Atom feeds are automatically generated for blog subscribers:

feedOptions: {
type: ['rss', 'atom'], // Generate both RSS and Atom feeds
xslt: true, // Style feeds for browser viewing
title: 'Pacing Agency Blog',
description: 'Digital marketing insights...',
copyright: `Copyright © ${new Date().getFullYear()} Pacing Agency`,
}

Feed URLs:

  • RSS: /blog/rss.xml
  • Atom: /blog/atom.xml

Note: Feed generation only works in production builds, not in development.

Best Practices Enforcement

onInlineTags: 'warn',              // Warn when tags not in tags.yml
onInlineAuthors: 'warn', // Warn when authors not in authors.yml
onUntruncatedBlogPosts: 'warn', // Warn when missing <!-- truncate -->

Options: 'ignore' | 'log' | 'warn' | 'throw'

Use 'throw' to enforce strict compliance (build will fail on violations).

File Structure

docusaurus/blog/
├── authors.yml # Author definitions
├── tags.yml # Tag definitions
├── YYYY-MM-DD-post-slug.mdx # Blog posts
└── .sync-manifest.json # Webflow sync tracking (gitignored)

docusaurus/static/img/blog/ # Blog images

Authors Configuration

Define authors in blog/authors.yml:

ben-power:
name: Ben Power
title: Founder, Pacing Agency
url: https://pacing.agency
image_url: https://pacing.agency/img/ben-power.jpg
socials:
github: benpower
x: benpower
linkedin: ben-power

pacing-agency:
name: Pacing Agency
title: Digital Marketing Agency
url: https://pacing.agency
image_url: https://pacing.agency/img/logo.svg

Supported social platforms:

  • github, x, twitter, linkedin, stackoverflow
  • instagram, bluesky, mastodon, threads
  • twitch, youtube, email

Use handles for pre-defined platforms:

socials:
github: slorber # Just the handle
x: sebastienlorber # Just the handle
linkedin: sebastienlorber # Just the handle

Tags Configuration

Define tags in blog/tags.yml:

channel-deep-dives:
label: 'Channel Deep Dives'
permalink: '/channel-deep-dives'
description: 'In-depth analysis of marketing channels and strategies'

data-analytics:
label: 'Data & Analytics'
permalink: '/data-analytics'
description: 'Technical insights on tracking, analytics, and data accuracy'

website-ux:
label: 'Website & UX'
permalink: '/website-ux'
description: 'Website design, development, and user experience topics'

Post Frontmatter

Blog posts support extensive frontmatter metadata:

---
slug: my-blog-post # URL slug (optional)
title: My Awesome Blog Post # Required
date: 2025-01-15 # Required (YYYY-MM-DD)
authors: # Use author keys from authors.yml
- ben-power
- cam-bowen
tags: # Use tag keys from tags.yml
- data-analytics
- website-ux
description: > # SEO meta description
Learn how to optimize your website analytics
for better insights and decisions.
image: /img/blog/featured.jpg # Featured/social image
hide_table_of_contents: false # Show TOC (default: false)
toc_min_heading_level: 2 # TOC min level (2-6)
toc_max_heading_level: 3 # TOC max level (2-6)
keywords: # SEO keywords
- analytics
- optimization
- tracking
draft: false # Draft posts (dev only)
unlisted: false # Hidden but accessible via direct link
---

Advanced Frontmatter

---
title_meta: Custom SEO Title # Override <title> for SEO
sidebar_label: Short Label # Custom sidebar label
last_update: # Override last update info
date: 2025-01-20
author: ben-power
---

URL Structure

  • Blog index: /blog
  • Blog post: /blog/my-blog-post
  • Tag pages: /blog/tags/data-analytics
  • Archive: /blog/archive
  • Author pages: /blog/authors/ben-power
  • RSS feed: /blog/rss.xml
  • Atom feed: /blog/atom.xml

Advanced Configuration

Custom Reading Time

readingTime: ({content, frontMatter, defaultReadingTime}) => {
// Custom reading time calculation
return defaultReadingTime({content, options: {wordsPerMinute: 250}});
}

Custom Feed Items

feedOptions: {
createFeedItems: async (params) => {
const {blogPosts, defaultCreateFeedItems, ...rest} = params;
return defaultCreateFeedItems({
// Keep only 10 most recent posts in feed
blogPosts: blogPosts.filter((item, index) => index < 10),
...rest,
});
},
}

Process Blog Posts

processBlogPosts: async ({blogPosts}) => {
// Filter, modify, or transform blog posts
return blogPosts.filter(post => !post.metadata.frontMatter.draft);
}

Custom Edit URL

editUrl: ({locale, blogDirPath, blogPath, permalink}) => {
return `https://github.com/org/repo/edit/main/website/${blogDirPath}/${blogPath}`;
}

MDX Plugins

Add Remark and Rehype plugins for extended Markdown functionality:

blog: {
remarkPlugins: [
require('remark-math'),
require('remark-gfm'),
],
rehypePlugins: [
require('rehype-katex'),
],
}

Localization

For multi-language blogs, translations are stored in:

website/i18n/[locale]/docusaurus-plugin-content-blog/
├── authors.yml # Translated authors
├── tags.yml # Translated tags
├── first-post.md # Translated posts
└── options.json # Translated plugin options

Best Practices

  1. Always use <!-- truncate --> in posts to control preview length
  2. Define authors in authors.yml rather than inline in frontmatter
  3. Define tags in tags.yml for consistency across posts
  4. Use descriptive slugs for SEO (avoid generic slugs like post-1)
  5. Add featured images for better social sharing (image frontmatter)
  6. Write good descriptions for SEO and social cards
  7. Use proper heading hierarchy (H2 → H3 → H4)
  8. Test feeds in production (feeds don't work in dev mode)
  9. Optimize images before uploading (use WebP/AVIF formats)
  10. Cross-link content to improve discoverability

Webflow Sync Integration

Blog posts are automatically synced from Webflow CMS using our custom sync script:

./scripts/resources/webflow/scripts/run-sync.sh

See the Webflow documentation in /scripts/resources/webflow/README.md for sync script details.

Troubleshooting

Feed not generating

Cause: Feeds only work in production builds Solution: Run npm run build and check build/blog/rss.xml

Author not showing

Cause: Author key doesn't match authors.yml Solution: Check spelling and ensure author exists in authors.yml

Tag page 404

Cause: Tag permalink doesn't match tag definition Solution: Verify tag key in tags.yml matches frontmatter

Post not truncating

Cause: Missing <!-- truncate --> marker Solution: Add truncate marker after intro paragraph

Reading time incorrect

Cause: Default calculation based on word count Solution: Customize with readingTime function in config