Writing a Post
Posts are the heart of a BlogMore blog. Each post is a Markdown file with a small block of metadata at the top called frontmatter. This page covers everything you need to know to write, format, and publish a post.
Your first post
Create a new .md file inside your content directory. The filename becomes part of the post's URL, so choose something descriptive and lowercase:
posts/hello-world.md
At its simplest, a post looks like this:
---
title: Hello World
date: 2024-01-15
---
Welcome to my new blog! This is my first post.
That's all you need to get started. BlogMore will generate a full HTML page from this file, including the page title, date, and all the surrounding navigation.
Frontmatter
Frontmatter is the block of YAML at the very top of your Markdown file, enclosed between two lines of ---. It tells BlogMore everything it needs to know about the post.
Required fields
title
The title of the post. This appears as the page heading, in the browser tab, and in listings, feeds, and search results.
title: My Thoughts on Python 3.12
Optional fields
date
The publication date of the post. Posts are sorted chronologically by this field, so it's well worth setting. Posts without a date appear after all dated posts.
date: 2024-01-15
See Date formats below for all accepted formats.
tags
A list of tags for the post. Tags are specific topics that can span across categories. Each tag gets its own page on the site listing all posts with that tag.
tags: [python, tutorial, beginner]
Tags can be written in several ways — see Tags formats below.
category
A single broad category for the post. Each category gets its own page listing all posts in it. A post can belong to at most one category.
category: python
See Categories and tags below for guidance on when to use each.
author
The name of the post's author. If not set, BlogMore falls back to the default_author set in your configuration.
Example:
author: Dave Pearson
author_url
The URL of the post's author. If not set, BlogMore falls back to the default_author_url set in your configuration.
Example:
author_url: https://davep.org/
show_author
Whether to show the author's name on this post. This property always overrides the global show_author setting in your configuration. If an author is set (either here or via default_author), the name is displayed below the date/time as "By {author name}".
Example:
show_author: true
draft
Set to true to mark the post as a draft. Draft posts are excluded from the build by default. This is useful for work in progress that you're not ready to publish.
draft: true
To include drafts during local development, pass --include-drafts on the command line or set include_drafts: true in your configuration. See Building and Publishing for more.
description
A short description of the post. Used for the <meta name="description"> tag, Open Graph tags, and Twitter Card tags. If not set, BlogMore falls back to the first paragraph of the post's content.
description: A gentle introduction to Python decorators with practical examples.
cover
A URL or path to a cover image, used for Open Graph, Twitter Card, and JSON-LD structured data. If not set, BlogMore falls back to the generated platform icons (if available) or the site_logo.
cover: /images/my-post-cover.png
twitter_creator
The Twitter/X handle of the post's author. Used in Twitter Card meta tags.
twitter_creator: "@davep"
twitter_site
The Twitter/X handle of the site. Used in Twitter Card meta tags.
twitter_site: "@my_blog"
modified
The date the post was last modified. Used in the <meta name="last-modified"> tag and displayed after the publication date on the post page and in all post listing summaries. Accepts the same formats as date.
When present, the modified date is shown in parentheses and italics after the publication date:
2026-04-27 08:40:40 UTC+01:00 (Modified: 2026-04-28 09:40:40 UTC+01:00)
modified: 2024-06-01
invite_comments
Override the global invite_comments setting for this post. Set to true to show the comment invitation section on this post even if it is disabled globally, or to false to hide it on this post even if it is enabled globally.
invite_comments: false
invite_comments_to
Override the email address used in the comment invitation link for this post. When set, this value is used as a literal email address — no template expansion is applied. This takes precedence over the global invite_comments_to setting.
invite_comments_to: "specific-address@example.com"
This key only has an effect when the comment invitation feature is enabled (either globally via invite_comments or via the per-post invite_comments front-matter key above).
show_toc
Whether to show the Table of Contents for this post. If not specified, this defaults to the global show_toc setting in your configuration (which itself defaults to true). Set to false to hide the Table of Contents on this specific post even if it contains headings, or to true to show it even if disabled globally.
show_toc: false
show_toc_inline
Whether to show the inline/collapsed Table of Contents on narrow screens for this post. If not specified, this defaults to the global show_toc_inline setting in your configuration (which itself defaults to true). Set to false to hide the inline Table of Contents on narrow displays for this specific post (while still showing the floating sidebar Table of Contents on wider displays, provided show_toc is enabled).
show_toc_inline: false
redirect_from
A list of URL paths (or a single URL path) that should redirect to this post. Fallback HTML redirection files containing a <meta http-equiv="refresh" content="0; url=..."> redirect and a canonical link tag will be written at these alias paths during the build process.
If the redirect path ends with a slash or has no extension, it will be treated as a directory and write an index.html file inside it. If it has a file extension (e.g. .html or .htm), it will write that file directly.
Examples:
# Redirect from legacy URLs
redirect_from:
- /2021/05/my-post/
- /old-category/my-post.html
Or a single path:
redirect_from: /old-post-slug
Date formats
BlogMore accepts dates in several formats:
date: 2024-01-15 # Simple date
date: 2024-01-15 14:30:00 # Date with time
date: 2024-01-15T14:30:00Z # ISO 8601 with timezone
All formats work for both date and modified.
Tags formats
Tags can be written in three ways — choose whichever you find most readable:
# Inline YAML list (recommended)
tags: [python, web, tutorial]
# Comma-separated string
tags: python, web, tutorial
# Multi-line YAML list
tags:
- python
- web
- tutorial
Categories and tags
Both categories and tags help visitors find related content, but they serve different purposes:
- Category — the broad subject area the post belongs to. Think of it as the section of a magazine:
python,devops,book-reviews. A post has at most one category. - Tags — specific topics within a post that might cut across categories. Think of them as an index:
tutorial,beginner,type-hints,testing. A post can have as many tags as you like.
A well-organised post might look like this:
---
title: Python Decorators Explained
category: python
tags: [tutorial, intermediate, decorators]
---
Visitors can navigate to /category/python.html to see all posts in that category, or to /tag/tutorial.html to see all posts tagged with tutorial.
Series
If you publish multi-part articles, you can group them into a cohesive series. Series membership is defined using the series frontmatter key.
A post can belong to a single series, or to multiple series.
Series formats
Like tags, series can be written as a single string (for a single series) or as a list:
# A single series title
series: Designing a Static Site Generator
# Multiple series (as a YAML list)
series: [Designing a Static Site Generator, Web Development Basics]
# Multiple series (as a multi-line YAML list)
series:
- Designing a Static Site Generator
- Web Development Basics
Navigation and sorting
Within each series, posts are automatically sorted in chronological order using their original posting date and time (the date frontmatter value; the modified date has no effect on sorting).
When generating post pages, BlogMore automatically adds a series banner at the top and bottom of each post belonging to a series. This banner displays a message (e.g. This post is part of the "Designing a Static Site Generator" series) and provides previous/next navigation links linking to other parts of the series.
Markdown features
BlogMore supports standard Markdown plus several extensions. The following sections cover the most useful ones.
Basic formatting
Standard Markdown formatting all works as expected:
**bold**, *italic*, `inline code`, ~~strikethrough~~
> Blockquote text
- unordered list
- second item
1. ordered list
2. second item
[link text](https://example.com)

Strikethrough
Wrap text in double tildes (~~) to render it with a line through it:
This is ~~deleted~~ and this is ~~struck-out text~~ in a sentence.
This produces text where the marked words appear with a horizontal line through them, rendered as an HTML <del> element. Use it to indicate content that has been removed or is no longer relevant.
Code blocks with syntax highlighting
Use fenced code blocks with a language identifier for syntax highlighting:
```python
def greet(name: str) -> str:
return f"Hello, {name}!"
```
A wide range of languages are supported, including python, javascript, typescript, bash, yaml, json, html, css, sql, rust, go, and many more.
Diagrams (Mermaid)
If enabled, BlogMore supports rendering diagrams and flowcharts written inside fenced code blocks using the mermaid language identifier:
```mermaid
graph TD
A[Start] --> B[Process]
B --> C{Decision}
C -->|Yes| D[Success]
C -->|No| E[Fail]
```
To use Mermaid diagrams:
- Enable the feature: You must turn on Mermaid rendering globally by setting
with_mermaid: truein yourblogmore.yamlconfiguration file. - Efficient loading: To keep page load speeds fast, the Mermaid JS library is only loaded from a CDN on pages (posts, pages, or index/listings) that actually contain a diagram block.
- More options: For full syntax details, layout options, and diagram types (such as sequence diagrams, pie charts, gantt charts, and user journeys), see the official Mermaid documentation.
LaTeX Math Rendering
If enabled, BlogMore supports rendering mathematical equations and formulas written in standard LaTeX notation:
- Inline math: Enclose the formula between single dollar signs, like
$e^{i\pi} + 1 = 0$(note: there must be no space immediately inside the delimiters). - Block math: Enclose the formula between double dollar signs on separate lines:
$$ f(x) = \int_{-\infty}^{\infty} \hat{f}(\xi) e^{2 \pi i x \xi} d\xi $$
To use LaTeX math equations:
- Enable the feature: You must turn on math rendering globally by setting
with_maths: truein yourblogmore.yamlconfiguration file. - Select a rendering engine: You can configure your preferred engine via
maths_provider(defaults to'katex'for instant rendering, or'mathjax'for full feature support and accessibility). - Efficient loading: To keep page load speeds fast, the chosen rendering library is only loaded from a CDN on pages that actually contain mathematical equations.
Tables
| Feature | Supported |
|---------------|-----------|
| Code blocks | Yes |
| Tables | Yes |
| Footnotes | Yes |
| Admonitions | Yes |
Footnotes
This is a statement that needs a citation.[^1]
[^1]: The source of the citation.
The footnote marker becomes a superscript link, and the footnote text is rendered at the bottom of the post.
Admonitions
BlogMore supports GitHub-style alert boxes, written as blockquotes with a special tag on the first line:
> [!NOTE]
> Useful information that readers should know.
> [!TIP]
> A helpful suggestion for doing things better.
> [!IMPORTANT]
> Key information that readers must not miss.
> [!WARNING]
> Urgent information that needs immediate attention.
> [!CAUTION]
> Advice about risks or negative outcomes.
Each type is rendered with a distinct colour scheme and icon so that readers can recognise them at a glance.
Heading IDs and anchor links
Every heading in a post automatically receives an id attribute derived from
its text. For example:
## Getting Started
becomes:
<h2 id="getting-started">Getting Started</h2>
This means you can link directly to any section of a post by appending its
fragment to the URL — for example
https://example.com/2024/01/15/my-post.html#getting-started.
Custom heading IDs
If you need a specific id — for example because the auto-generated one is too
long, or because you want a stable id that won't change if you reword the
heading — you can set it explicitly by appending {#your-id} to the end of the
heading line:
### My Great Heading {#custom-id}
This produces:
<h3 id="custom-id">My Great Heading</h3>
The custom id overrides the auto-generated one. Headings without a {#…}
suffix keep their auto-generated IDs as usual.
Hover anchor links
To make it easy for readers to share a link to a specific section, BlogMore renders a small ¶ symbol at the end of every heading. The symbol is invisible by default and appears when the reader moves the mouse over the heading. Clicking the symbol navigates the browser to that heading's URL fragment, where the address can be copied from the browser's location bar.
The anchor appears and disappears with a smooth fade and does not affect the layout of the page in any way.
Table of Contents
For long posts with many sections, a table of contents makes it easy for readers to navigate your content. It provides a quick overview of the post's structure and lets users jump directly to any heading.
Syntax
To insert a table of contents, place [TOC] on its own line in your Markdown file:
# My Long Article
Here is an overview of what we will cover:
[TOC]
## Section One
...
## Section Two
...
How it works
BlogMore automatically scans your post for all headings (# through ######) and generates a Table of Contents.
- Sidebar & Responsive TOC: By default, on desktop displays, a floating, sticky Table of Contents is shown in the right-hand margin of the page. On smaller mobile screens, this TOC is presented inline at the top of the post under a collapsible accordion.
- Manual TOC: You can also insert the TOC manually at a specific place inside the post content by placing
[TOC]on its own line. - Disabling the TOC: If you have headings but do not want a Table of Contents to be displayed at all (neither floating nor inline), you can disable it globally in your configuration or set the
show_tocproperty tofalsein the post's frontmatter:show_toc: false - Disabling the inline TOC only: If you want to keep the floating sidebar TOC on wider screens but hide the inline/collapsed TOC on narrow displays, you can disable it globally in your configuration or set the
show_toc_inlineproperty tofalsein the post's frontmatter:show_toc_inline: false - The links target the automatically generated heading IDs (see Heading IDs and anchor links above).
- The generated list is automatically nested based on heading levels (e.g.,
###headings are nested under##headings). - The table of contents is pre-styled to match your blog's theme, with hover effects and responsive indentation.
Markdown inside HTML tags
By default, Markdown inside raw HTML blocks is left as-is and is not processed
further. If you want Markdown to be parsed inside an HTML element, add
markdown="1" to the opening tag:
<div markdown="1">
*This text will be italic* and **this will be bold**.
</div>
<center markdown="1">
*This centered text will be italic* and **this will be bold**.
</center>
Without markdown="1", any Markdown inside the HTML tag is passed through
verbatim and will not be rendered. With the attribute present, the content is
treated as normal Markdown and all the usual formatting rules apply.