Blog, Tags and Plugins

This content was generated with the assistance of AI and should be verified against the official documentation of each tool before being relied on in production.

This section’s bibliography lists the reference material consulted while preparing these pages.

Zensical does not load MkDocs plugins. It re-implements the most used ones in its own core, so the blog, the tags and a list of other features are enabled through the same plugins setting that Material for MkDocs users know, but they run natively. This page was written against Zensical 0.0.72 (the latest release on PyPI) and checked on 2026-10-26. The examples add a blog and tags to Pocket Units, a tiny units-conversion library for C# and Python, and were built with Zensical 0.0.72 on Python 3.13.

What a plugin is in Zensical

In MkDocs a plugin is a Python package that hooks into the build. Zensical runs in a Rust core and does not execute arbitrary MkDocs plugins or expose the MkDocs plugin API. Instead, the project lists the plugins it implements natively on its compatibility page, and a separate Module API is planned for extensions in the future. A plugin is enabled in zensical.toml with a table named [project.plugins.<name>], or in mkdocs.yml with the usual plugins: list. The configuration page describes the file formats.

A plugins entry is checked against the supported list: supported plugins run natively and reject unknown settings, unlisted plugins are ignored silently

The figure summarises how an entry of the plugins setting is treated. Everything outside the supported list is dropped without a message, which is the main pitfall when migrating.

Native blog

The blog is a native port of the blog plugin of Material for MkDocs. It reproduces that plugin’s configuration and behaviour, so the Material documentation remains the reference for detailed options. The Zensical documentation states that more flexible blogging functionality designed for Zensical is planned. The plugin offers posts, archives, categories, author profiles and pagination. No extra Python package is needed.

Folder layout

Posts live in docs/blog/posts/ (nested folders are allowed) and the blog entry point is docs/blog/index.md. Authors are described in docs/blog/.authors.yml. The URL of a post is computed from its title, date and the configured URL format, not from its source path.

docs/
  index.md
  tags.md
  blog/
    index.md
    .authors.yml
    posts/
      release-1-0.md

With automatic navigation nothing else is required. With an explicit nav, add only the blog entry point, never the individual posts.

Enabling the blog

The following zensical.toml enables the blog and the tags plugins for Pocket Units. The options blog_dir, post_date_format, post_url_format, post_excerpt, pagination_per_page, archive and categories are options of the Material blog plugin; they were accepted by Zensical 0.0.72. The table some-unknown-plugin demonstrates a plugin that Zensical does not know.

zensical.toml
[project]
site_name = "Pocket Units"
site_url = "https://example.org/pocket-units/"
nav = [
  { "Home" = "index.md" },
  { "Blog" = "blog/index.md" },
  { "Tags" = "tags.md" },
]

[project.plugins.blog]
blog_dir = "blog"
post_date_format = "long"
post_url_format = "{date}/{slug}"
post_excerpt = "optional"
pagination_per_page = 5
archive = true
categories = true

[project.plugins.tags]

[project.plugins.some-unknown-plugin]
anything = "is silently ignored"

[project.extra.tags]
Python = "python"
CSharp = "csharp"

[project.theme.icon.tag]
python = "fontawesome/brands/python"
csharp = "fontawesome/solid/code"
default = "fontawesome/solid/tag"

Posts, authors and excerpts

Every post needs a date (a single value, or created and updated). Other front matter keys are categories and authors (identifiers from .authors.yml), links for related links in the post sidebar, and draft: true. A draft is shown in preview but excluded from normal builds. Content before the <!-- more --> separator is the excerpt shown in blog views; without a separator the whole post is used unless excerpts are required.

docs/blog/posts/release-1-0.md
---
date: 2026-10-01
authors:
  - alberto
categories:
  - Releases
tags:
  - Python
---

# Pocket Units 1.0

The first stable release converts lengths between meters and feet.

<!-- more -->

Details of the release follow here.
docs/blog/.authors.yml
authors:
  alberto:
    name: Alberto
    description: Maintainer
    avatar: https://example.org/avatar.png

A second post with draft: true was added to the test project. The build produced these blog files, and the draft was absent from the output:

site/blog/index.html
site/blog/2026/10/01/pocket-units-10/index.html
site/blog/archive/2026/index.html
site/blog/category/releases/index.html

The index page shows the excerpt of the post only, while the post page contains the full text. Posts can link to each other by source path and assets beside posts are moved to the generated blog assets directory. Archive, category and author pages list their posts in chronological order, and the index is paginated.

Native tags

The tags plugin is the native version of the Material tags plugin. Add a tags list to the front matter of any page; the tags are shown at the bottom of the page and can be used to filter search results. A page can hide its tags by adding tags to its hide front matter list.

docs/index.md
---
tags:
  - Python
  - CSharp
---

# Pocket Units

A tiny units-conversion library.

Tag icons are optional. The table extra.tags maps a tag to an identifier (letters, digits, dashes and underscores only) and theme.icon.tag assigns an icon to each identifier, with default as the fallback; several tags may share one identifier. The configuration above does exactly this. A listing page is created with the marker used by the Material plugin:

docs/tags.md
# Tags

<!-- material/tags -->

The build rendered the tags of the home page as md-tag--python and md-tag--csharp elements and a tag listing page at site/tags/index.html. The Zensical page does not describe the listing syntax; it refers to the Material documentation for listings and advanced settings. The legacy tag settings tags_compare, tags_compare_reverse, tags_pages_compare, tags_pages_compare_reverse, tags_file, tags_extra_files, export, export_file and export_only are ignored, and custom callables are unsupported. A build with tags_compare_reverse = true completed without a message.

Supported plugins

According to the compatibility page, 31 plugins are implemented natively. Settings that are documented as ignored are dropped silently, with no value validation or warnings.

Plugin Notes on differences

api-autonav

API pages and navigation through mkdocstrings. api_root_uri must be a nonempty relative subdirectory.

audio

Configured as mkdocs-audio. Settings audio_type, audio_controls, audio_autoplay.

autoapi

Configured as mkdocs-autoapi. Generates API pages through mkdocstrings. autoapi_root has the same restriction.

autorefs

Cross-references with [text][identifier]. link_titles and strip_title_tags default to auto.

awesome-nav

Per-directory .nav.yml. Extglob is unsupported; not_in_nav does not apply to generated navigation.

blog

Posts, archives, categories, authors, pagination. Custom Python callables are unsupported; built-in strategies only.

callouts

Obsidian-style callouts as admonitions. Ignores aliases, breakless_lists and title_from_first_bold.

exclude

Excludes paths by glob (globset syntax) or regex relative to docs_dir.

gh-admonitions

GitHub-style alerts as admonitions.

glightbox

Image lightbox. Ignores touchNavigation, loop, effect, slide_effect, zoomable, draggable, background and shadow.

include-markdown

Converts include tags to Snippets. Per-inclusion arguments, globs, exclude, order, recursive and others are not applied.

literate-nav

Navigation from SUMMARY.md link lists.

llmstxt

Generates llms.txt and Markdown copies of pages. preprocess is ignored.

macros

Jinja and Python macros. A new environment per page; only define_env runs, the page and build hooks do not.

markdown-exec

Executes fenced code blocks. Install markdown-exec[ansi] for ANSI output.

markdownextradata

Jinja rendering in Markdown and titles. Data outside the project root is skipped.

meta

Shared front matter through .meta.yml. Custom YAML tags are unsupported.

mike

Versioning. Requires a compatible fork; ignores css_dir and javascript_dir.

minify

Minifies HTML, JS and CSS. minify_inline_js and minify_inline_css exist only in Zensical.

mkdocstrings

API documentation from source. Install mkdocstrings-python for Python. Ignores watch.

nav-weight

Configured as mkdocs-nav-weight. Ordering, titles and visibility from metadata.

offline

Makes search work when the site is opened from the file system.

privacy

Self-hosts external assets and annotates external links. The cache format differs from Material.

redirects

Redirect maps, with anchor-based redirects for moved sections.

rss

RSS and JSON feeds. Ignores cache_dir and use_material_social_cards.

social

Social cards and Open Graph metadata.

search

Enabled by default even if unlisted. Only enabled and separator apply; the language comes from theme.language.

section-index

Built in natively; the entry can stay in shared configuration but is ignored.

table-reader

Embeds data files as tables. All files must be inside the project.

tags

Native tags, with the legacy settings listed above ignored.

video

Configured as mkdocs-video. Remote players through iframe, or native video with is_video: true.

The search plugin is covered in Search, the mkdocstrings family in API Docs with mkdocstrings and mike in Versioning and i18n.

Unsupported, planned and in-progress plugins

Plugin Status Alternative

gen-files

Unsupported

Use autoapi or api-autonav for API pages, or run generation scripts separately.

open-in-new-tab

Unsupported

Add its JavaScript with extra_javascript.

git-authors

Planned

None yet.

git-committers

Planned

None yet.

git-revision-date-localized

Planned

None yet.

optimize

In progress

None yet.

Silently ignored plugins

Configuration for a plugin that is not in the supported list is ignored without any message: Zensical neither imports nor runs it. The test project above contains some-unknown-plugin and built with the output No issues found. A migrated mkdocs.yml that lists, for example, a custom or third-party plugin therefore builds, but the feature is missing from the site. Compare the plugin list with the tables above before trusting a migrated build.

The opposite case is strict: a supported plugin rejects a setting it does not know. Adding bogus_setting = 1 to [project.plugins.blog] stopped the build with a Python traceback that ended with this line:

ValueError: invalid plugins.blog.bogus_setting: is not a supported option

Settings listed as ignored for a supported plugin are different: they are accepted and dropped, for example the legacy tags_compare_reverse.

Pitfalls and version notes

  • Zensical is in alpha at 0.0.72; the plugin list grows with releases, so check the compatibility page again after an upgrade.

  • Build hooks and the MkDocs plugin API are not available. The page on migrating from Material for MkDocs lists the other gaps.

  • The blog is a port of the Material for MkDocs blog, which is in maintenance mode; Zensical-specific blogging is planned but not yet documented.

  • Custom Python callables (blog strategies, tag sorting) are unsupported.