Custom plugins
plugins#
# config.py file
from mkdocs.config.base import Config
# from mkdocs.config.config_options import Deprecated, Type
class MyPluginConfig(Config):
enabled = Type(bool, default = True)
cards = Type(bool, default = True)
cards_dir = Type(str, default = "assets/images/social")
cards_layout_options = Type(dict, default = {})
# cards_color = Deprecated(
# option_type = Type(dict, default = {}),
# message =
# "Deprecated, use 'cards_layout_options.background_color' "
# "and 'cards_layout_options.color' with 'default' layout"
# )
Source - https://github.com/squidfunk/mkdocs-material/blob/master/src/plugins/social/config.py
# plugin.py file
from mkdocs.plugins import BasePlugin
from .config import SocialConfig
class MyPluginPlugin(BasePlugin[MyPluginConfig]):
def __init__(self):
# ---------------------------- Retrieve configuration ------------------------------
def on_config(self, config):
# Move color options (Deprecated)
if self.config.cards_color:
# ---------------------------- Create social cards ---------------------------------
def on_page_content(self, html, page, config, files):
# Compute page title and description
title = page.meta.get("title", page.title)
description = config.site_description or ""
if "description" in page.meta:
description = page.meta["description"]
# ---------------------------- Check results of executors ---------------------------
def on_post_build(self, config):
if not self.config.cards:
return
# Check for exceptions
for promise in self._image_promises:
promise.result()
# -------------------------------------------------------------------------
Events / Hooks#
| Configuration and Setup Events | Description |
|---|---|
| on_config(config) | Called after the config is loaded and validated. Modify or inspect the configuration here. |
| on_pre_build(config) | Called before any build actions are taken. Good for setup tasks. |
| on_files(files, config) | Called after files are collected but before being processed. You can add, remove, or modify files here. |
| on_nav(nav, config, files) | Called after navigation is created. Can be used to modify the site structure. |
| on_env(env, config, files) | Called after the Jinja2 environment is created. Useful for adding custom filters or globals. |
| Page-level Events | Description |
|---|---|
| on_page_markdown(markdown, page, config, files) | Called after the markdown source is read but before conversion. Great for preprocessing markdown. |
| on_page_content(html, page, config, files) | Called after markdown is converted to HTML, but before being passed to the template. |
| on_page_context(context, page, config, nav) | Called before a page is rendered. You can modify the Jinja2 context here. |
| on_post_page(output, page, config) | Called after the page is rendered and HTML is generated. Can be used to post-process HTML or store metadata. |
| Build & Output Events | Description |
|---|---|
| on_post_build(config) | Called after the site is built but before files are written to disk. Useful for cleanup or final analysis. |
| on_post_build_environment(env, config) | Called after build environment is finalized. Useful for teardown. |
| on_post_build_site(config) | Called after everything has been built and written. Rarely used, but useful for post-processing outputs. |
| on_post_build_commands(config) | Called after shell commands in the config are executed. |
| on_serve(server, config, builder) | Called when running mkdocs serve. Allows you to modify the dev server. |
| on_pre_template(context) | Internal use; rarely needed. |
| on_post_template(context) | Internal use; rarely needed. |
| on_page_read_source(path, config) | If you want to override how a page source is read (e.g., dynamic content). |
Event workflow#
on_config
↓
on_pre_build
↓
on_files
↓
on_nav
↓
on_env
↓
┌────────────────────────────┐
│ For each page │
│ │
│ → on_page_markdown │
│ → on_page_content │
│ → on_page_context │
│ → on_post_page │
└────────────────────────────┘
↓
on_post_build
on_page_markdown#
Called after the markdown source is read but before conversion. Great for preprocessing markdown.
ReplaceTOCPlugin#
Plugin Code
from mkdocs.plugins import BasePlugin
class ReplaceTOCPlugin(BasePlugin):
def on_page_markdown(self, markdown, page, config, files):
# Replace a custom placeholder with a fixed string
updated_markdown = markdown.replace('{{TOC}}', '**Table of Contents will go here**')
return updated_markdown
Configuration (mkdocs.yml snippets)
Input markdown file example
Expected markdown output
on_page_context#
Called before a page is rendered. You can modify the Jinja2 context here.
SourcePagePlugin#
This plugin will:
- Access page.file during the on_page_context event.
- Extract the source file path (src_uri) and destination URL (url).
- Inject it into the page context so you can use it in your templates.
# Create a plugin in plugins/source_path.py:
from mkdocs.plugins import BasePlugin
class SourcePathPlugin(BasePlugin):
def on_page_context(self, context, page, config, nav, **kwargs):
file = page.file
# Extract info from page.file
source_info = {
'abs_src_path': file.abs_src_path,
'src_uri': file.src_uri,
'dest_uri': file.dest_uri,
'url': file.url,
'name': file.name,
'edit_url': file.edit_url
}
# Add it to the context
context['source_info'] = source_info
return context
# Update mkdocs.yml to register the plugin:
plugins:
- search
- source-path:
enabled: true
# If your plugin is not pip-installed, point to the file:
plugins_dir: plugins
# Use it in your custom theme (Jinja2 template):
# Inside your main.html or a custom page.html, insert:
{% if source_info %}
<div class="source-debug">
<h4>Page Debug Info</h4>
<ul>
<li><strong>Source file:</strong> {{ source_info.src_uri }}</li>
<li><strong>Destination URL:</strong> {{ source_info.url }}</li>
<li><strong>Edit URL:</strong> <a href="{{ source_info.edit_url }}">{{ source_info.edit_url }}</a></li>
</ul>
</div>
{% endif %}
on_page_content event#
Called after markdown is converted to HTML, but before being passed to the template.
This is great for:
- Adding disclaimers
- Inserting custom banners
- Tracking tags (like analytics)
- Warnings or notices
FooterInjector Plugin#
Appends a custom HTML footer to every page's content, after Markdown has been converted to HTML but before the template is applied.
from mkdocs.plugins import BasePlugin
class FooterInjectorPlugin(BasePlugin):
def on_page_content(self, html, page, config, files):
# Define the custom HTML you want to inject
footer_html = """
<div style="margin-top: 2em; padding: 1em; border-top: 1px solid #ccc; font-size: 0.9em; color: gray;">
<p>📘 Documentation generated by MkDocs.</p>
<p>Last updated: {{ page.meta.last_updated if page.meta.last_updated else "unknown" }}</p>
</div>
"""
# Append the HTML footer to the end of the page's content
return html + footer_html