Unleash the power of MkDocs with macros and variables
—
Interface for defining custom variables, macros, and filters in Python modules. Provides the primary extension mechanism for adding functionality to the template environment.
The main entry point for defining template functionality in Python modules.
def define_env(env):
"""
Primary hook for module definition.
Args:
env: MacrosPlugin instance with access to variables, macros, filters
This function is called during plugin initialization and must be present
in the module for it to be loaded successfully.
"""Basic module definition:
# main.py
def define_env(env):
"""Define variables, macros, and filters"""
# Add variables
env.variables['version'] = '1.0.0'
env.variables['author'] = 'John Doe'
# Define macro using decorator
@env.macro
def greeting(name):
return f"Hello, {name}!"
# Define filter using decorator
@env.filter
def uppercase(text):
return text.upper()
# Direct registration with custom name
def calculate_discount(price, percent):
return price * (1 - percent / 100)
env.macro(calculate_discount, 'discount')Advanced module with debugging:
def define_env(env):
"""Advanced module with debug capabilities"""
# Enable debug output
chatter = env.start_chatting('MY_MODULE')
chatter("Module loading started")
# Access configuration
if env.conf.get('site_name'):
env.variables['site_title'] = env.conf['site_name'].upper()
# Complex macro with error handling
@env.macro
def include_file(filename, start_line=0, end_line=None):
"""Include file content with optional line range"""
try:
full_path = os.path.join(env.project_dir, filename)
with open(full_path, 'r') as f:
lines = f.readlines()
return ''.join(lines[start_line:end_line])
except FileNotFoundError:
return f"File not found: {filename}"
chatter("Module loaded successfully")Optional hooks for pre and post-processing pages during rendering.
def on_pre_page_macros(env):
"""
Called before macro rendering for each page.
Args:
env: MacrosPlugin instance with page context available
The env.page and env.markdown properties are available.
Can modify env.markdown to alter page content before template rendering.
"""
def on_post_page_macros(env):
"""
Called after macro rendering for each page.
Args:
env: MacrosPlugin instance with page context available
The env.page and env.markdown properties are available.
Can modify env.markdown to alter final page content.
"""Adding dynamic content:
def on_pre_page_macros(env):
"""Add dynamic header before processing"""
header = f"\\n## Page: {env.page.title}\\nLast built: {{{{ now() }}}}\\n"
env.markdown = header + env.markdown
def on_post_page_macros(env):
"""Add footer after processing"""
footer = f"\\n\\n---\\n*Generated on {env.page.file.src_path}*"
env.markdown += footerConditional processing:
def on_pre_page_macros(env):
"""Conditional page modifications"""
# Only process API docs
if env.page.file.src_path.startswith('api/'):
env.markdown = "{% include 'api_header.md' %}\\n" + env.markdown
# Add warnings for draft pages
if 'draft' in env.page.meta:
warning = "!!! warning\\n This page is a draft\\n\\n"
env.markdown = warning + env.markdownOptional hook called after the entire site build is complete.
def on_post_build(env):
"""
Called after the complete site build.
Args:
env: MacrosPlugin instance
No page context available. Used for cleanup, file generation,
or other post-build operations.
"""Generate additional files:
def on_post_build(env):
"""Generate sitemap or other files"""
import json
# Generate metadata file
metadata = {
'build_time': str(env.variables.get('now', 'unknown')),
'site_name': env.conf.get('site_name'),
'pages': len(env.variables.get('navigation', {}).get('pages', []))
}
output_path = os.path.join(env.project_dir, 'site', 'metadata.json')
with open(output_path, 'w') as f:
json.dump(metadata, f, indent=2)Cleanup operations:
def on_post_build(env):
"""Post-build cleanup"""
temp_dir = os.path.join(env.project_dir, 'temp_build_files')
if os.path.exists(temp_dir):
shutil.rmtree(temp_dir)Deprecated but still supported module definition interface.
def declare_variables(variables, macro):
"""
Legacy hook for module definition (deprecated).
Args:
variables: Dictionary to add variables to
macro: Decorator function for registering macros
Prefer define_env() for new modules.
"""def declare_variables(variables, macro):
"""Legacy module definition (prefer define_env)"""
variables['legacy_var'] = 'value'
@macro
def legacy_function():
return "This uses the old API"Modules are loaded from the project directory:
main.py in project rootmain/ directory with __init__.pymodule_name in configurationPre-installed modules distributed via PyPI:
plugins:
- macros:
modules:
- package_name # Import as package_name
- source_name:import_name # Install source_name, import as import_nameThe plugin will automatically install missing packages using pip.
The plugin looks for these functions in order:
define_env(env) - Primary hook (required)on_pre_page_macros(env) - Optional pre-processingon_post_page_macros(env) - Optional post-processingon_post_build(env) - Optional build completionAt least define_env must be present for the module to load successfully.
# Module not found
raise ImportError("Macro plugin could not find custom 'module_name' module")
# No standard functions found
raise NameError("None of the standard functions was found in module")
# Function registration conflicts
raise KeyError("Registration error: macro 'name' already exists")define_env - Required for module loadingInstall with Tessl CLI
npx tessl i tessl/pypi-mkdocs-macros-plugin