Skip to content

Macros Plugin

Jinja2 templating and variables in Markdown.

Core Attributes

Plugin Name

macros

Installation

Bash
pip install mkdocs-macros-plugin

Configuration

YAML
plugins:
  - macros:
      module_name: docs/macros
      include_dir: docs/includes
      include_yaml: []
      j2_block_start_string: '{%'
      j2_block_end_string: '%}'
      j2_variable_start_string: '{{'
      j2_variable_end_string: '}}'

What It Does

The Macros plugin enables: - Define reusable variables - Create custom macros (functions) - Include external files - Use Jinja2 templating - Generate dynamic content

Variables

Defining Variables

Create docs/macros.py:

Python
def define_env(env):
    """Define custom variables"""
    env.variables['version'] = '2.0.0'
    env.variables['api_url'] = 'https://api.example.com'
    env.variables['company'] = 'Your Company'
    env.variables['year'] = 2024

Using Variables

In any markdown file:

Markdown
Current version: {{ version }}

API endpoint: {{ api_url }}

Copyright {{ year }} {{ company }}

Result:

Text Only
Current version: 2.0.0
API endpoint: https://api.example.com
Copyright 2024 Your Company

Macros (Functions)

Simple Macro

Python
def define_env(env):
    @env.macro
    def greet(name):
        return f"Hello, {name}!"

Usage:

Markdown
{{ greet("World") }}

Advanced Macro

Python
@env.macro
def button(text, link, style="primary"):
    """Create a Material button"""
    return f'[{text}]({link}){{ .md-button .md-button--{style} }}'

Usage:

Markdown
{{ button("Get Started", "/guides/", "primary") }}
{{ button("Learn More", "/docs/", "secondary") }}

Code Example Macro

Python
@env.macro
def code_example(filename, language="python"):
    """Insert code from file"""
    with open(f"examples/{filename}") as f:
        code = f.read()
    return f"```{language}\n{code}\n```"

Usage:

Markdown
{{ code_example("hello.py") }}

Built-in Variables

MkDocs provides several built-in variables:

Markdown
Page title: {{ page.title }}
Page URL: {{ page.url }}
Site name: {{ config.site_name }}
Site URL: {{ config.site_url }}
Repository URL: {{ config.repo_url }}

Includes

Basic Include

Create docs/includes/warning.md:

Markdown
!!! warning
    This feature is experimental.

Use in pages:

Markdown
{% include 'warning.md' %}

Parameterized Include

Create docs/includes/api_endpoint.md:

Markdown
**Endpoint:** `{{ method }} {{ endpoint }}`

{{ description }}

Use with context:

Markdown
{% set method = "GET" %}
{% set endpoint = "/api/users" %}
{% set description = "Retrieve all users" %}
{% include 'api_endpoint.md' %}

Advanced Examples

Dynamic Table

Python
@env.macro
def feature_table(features):
    """Generate feature comparison table"""
    rows = ["| Feature | Free | Pro |", "|---------|------|-----|"]
    for name, free, pro in features:
        rows.append(f"| {name} | {free} | {pro} |")
    return "\n".join(rows)

Usage:

Markdown
{{ feature_table([
    ("Users", "5", "Unlimited"),
    ("Storage", "1GB", "100GB"),
    ("Support", "Community", "Priority")
]) }}

API Documentation

Python
@env.macro
def api_endpoint(method, path, description, params=None):
    """Document API endpoint"""
    output = [f"### {method} {path}", "", description, ""]

    if params:
        output.append("**Parameters:**")
        output.append("")
        for name, type_, desc in params:
            output.append(f"- `{name}` (*{type_}*): {desc}")
        output.append("")

    return "\n".join(output)

Usage:

Markdown
{{ api_endpoint(
    "POST",
    "/api/users",
    "Create a new user",
    [
        ("name", "string", "User's full name"),
        ("email", "string", "User's email address")
    ]
) }}

Version Badge

Python
@env.macro
def version_badge(version, status="stable"):
    """Create version badge"""
    colors = {
        "stable": "green",
        "beta": "yellow",
        "alpha": "red"
    }
    color = colors.get(status, "blue")
    return f'<span class="badge badge-{color}">{version}</span>'

Filters

Custom Filters

Python
@env.filter
def uppercase(text):
    """Convert to uppercase"""
    return text.upper()

@env.filter
def format_date(date_obj):
    """Format date"""
    return date_obj.strftime("%B %d, %Y")

Usage:

Markdown
{{ "hello" | uppercase }}

{{ some_date | format_date }}

Conditional Content

Markdown
{% if config.site_url == "https://example.com" %}
Production content here
{% else %}
Development content here
{% endif %}

Loops

Markdown
{% for item in navigation %}
- {{ item.title }}
{% endfor %}

YAML Variables

Load variables from YAML:

docs/data/config.yaml:

YAML
api:
  version: 2.0
  base_url: https://api.example.com
  endpoints:
    - users
    - posts
    - comments

Config:

YAML
plugins:
  - macros:
      include_yaml:
        - docs/data/config.yaml

Usage:

Markdown
API Version: {{ api.version }}
Base URL: {{ api.base_url }}

Endpoints:
{% for endpoint in api.endpoints %}
- {{ endpoint }}
{% endfor %}

Best Practices

1. Organize Macros

Python
# docs/macros.py
def define_env(env):
    # Variables
    env.variables['version'] = '2.0'

    # UI Macros
    @env.macro
    def button(text, link):
        ...

    @env.macro
    def badge(text):
        ...

    # Content Macros
    @env.macro
    def include_code(file):
        ...

2. Document Macros

Python
@env.macro
def api_link(endpoint):
    """
    Create link to API endpoint.

    Args:
        endpoint: API endpoint path

    Returns:
        Formatted markdown link
    """
    return f"[{endpoint}]({{{{ api_url }}}}{endpoint})"

3. Error Handling

Python
@env.macro
def safe_include(filename):
    """Include file with error handling"""
    try:
        with open(f"includes/{filename}") as f:
            return f.read()
    except FileNotFoundError:
        return f"*File not found: {filename}*"

4. Use Includes for Reusability

Create includes for: - Common warnings - Standard sections - Repeated content - Boilerplate text

5. Keep Logic Simple

Complex logic belongs in Python:

Python
@env.macro
def complex_calculation(data):
    # Do complex work in Python
    result = process(data)
    return format_output(result)

Simple logic can stay in Markdown:

Markdown
{% if version >= 2.0 %}
New feature available!
{% endif %}

Use Cases

  1. Version numbers: Define once, use everywhere
  2. API URLs: Environment-specific endpoints
  3. Code examples: Include from files
  4. Dynamic tables: Generate from data
  5. Repeated content: Reduce duplication
  6. Conditional docs: Different content per environment