A MkDocs plugin that injects the mkdocs.yml extra variables into the markdown template
npx @tessl/cli install tessl/pypi-mkdocs-markdownextradata-plugin@0.2.0A MkDocs plugin that enables injection of configuration variables and external data files directly into markdown templates during site generation. It allows users to define variables in mkdocs.yml or external YAML/JSON files and reference them in markdown content using Jinja2 template syntax.
pip install mkdocs-markdownextradata-plugin# Plugin is automatically loaded by MkDocs when configured
# No direct imports needed for basic usage
# Plugin is registered as entry point: 'markdownextradata = markdownextradata.plugin:MarkdownExtraDataPlugin'Configure the plugin in your mkdocs.yml:
plugins:
- search
- markdownextradataDefine variables in mkdocs.yml:
extra:
customer:
name: "Your Company"
web: "www.example.com"
version: "1.0.0"Use variables in markdown files:
# Welcome to {{ customer.name }}
Visit us at: {{ customer.web }}
Current version: {{ customer.version }}Configure the plugin with custom data sources and Jinja2 options.
class MarkdownExtraDataPlugin(BasePlugin):
"""
MkDocs plugin for injecting extra variables into markdown templates.
Configuration Schema:
- data: Optional[str] - Data source folders (comma-separated paths)
- jinja_options: Optional[Dict] - Jinja2 template engine configuration
"""
config_scheme = (
("data", mkdocs.config.config_options.Type(str_type, default=None)),
("jinja_options", mkdocs.config.config_options.Type(dict, default={}))
)
# Python 2/3 compatibility
# str_type = str (Python 3+) or mkdocs.utils.string_types (Python 2)Configuration Examples:
# Basic configuration
plugins:
- markdownextradata
# With custom data directory
plugins:
- markdownextradata:
data: path/to/datafiles
# With multiple data directories
plugins:
- markdownextradata:
data: path/to/datafiles, another/path/to/datafiles
# With custom Jinja2 options
plugins:
- markdownextradata:
jinja_options:
comment_start_string: "__CUSTOMCOMMENTSTART__"
variable_start_string: "<<"
variable_end_string: ">>"Automatically loads data from configured sources and processes external files during the pre-build phase.
def on_pre_build(self, config, **kwargs):
"""
Load data from configured directories or default _data folders.
Args:
config: mkdocs configuration object
**kwargs: Additional keyword arguments from MkDocs
Data Processing:
1. Parse comma-separated data paths from 'data' config option
2. Convert relative paths to absolute paths based on config file location
3. If no data paths configured, search default locations:
- {config_file_dir}/_data
- {docs_dir}/_data
4. Load all .yml, .yaml, .json files recursively
5. Create namespaced variables based on file path structure
Supported file formats: .yml, .yaml, .json
Namespace mapping: File path becomes variable namespace
"""Default Data Locations:
./docs/_data/ (relative to mkdocs.yml)./_data/ (in project root)File-to-Namespace Mapping:
_data/site.yaml → {{ site.variable }}_data/sections/captions.yaml → {{ sections.captions.variable }}_data/1_example/data.yaml → {{ extra['1_example']['data']['variable'] }}Applies Jinja2 template substitution to markdown content and page titles.
def on_page_markdown(self, markdown, page, **kwargs):
"""
Apply template substitution to page content and title.
Args:
markdown: str - Raw markdown content
page: mkdocs.structure.pages.Page - Page object
Returns:
str: Processed markdown with variables substituted
"""
def apply_template(self, template_string):
"""
Apply Jinja2 substitution to specified string.
Args:
template_string: str - String containing Jinja2 template syntax
Returns:
str: Processed string with variables substituted
Template Context:
- All mkdocs config variables (site_name, site_author, etc.)
- All extra variables from mkdocs.yml
- All loaded data from external files
Raises:
jinja2.exceptions.TemplateSyntaxError: When template syntax is invalid.
Displays helpful error message suggesting use of 'extra' dictionary
for non-Python-compliant variable names.
"""Initializes the Jinja2 environment with custom options and prepares the MkDocs configuration.
def on_config(self, mkdocsConfig, **kwargs):
"""
Initialize Jinja2 environment and store MkDocs configuration.
Args:
mkdocsConfig: mkdocs.config.Config - MkDocs configuration object
Sets up:
- Jinja2.Environment with DebugUndefined and custom options
- Access to mkdocs config and extra variables
"""Variables defined in mkdocs.yml extra section:
extra:
site_name: "My Site"
author: "John Doe"Site: {{ site_name }}
Author: {{ author }}External data files create namespaced variables:
# _data/company/info.yaml
name: "ACME Corp"
founded: 2020Company: {{ company.info.name }}
Founded: {{ company.info.founded }}For non-Python-compliant names or safe access:
<!-- For files/folders starting with numbers or containing special characters -->
Value: {{ extra['1_example']['data']['key'] }}
<!-- Alternative access for any variable -->
Site: {{ extra['site_name'] }}The plugin provides helpful error messages for common issues:
# Template syntax errors with guidance
jinja2.exceptions.TemplateSyntaxError:
"ERROR\t- markdownextradata - One or more yaml files might not comply with "
"Python's variable naming conventions. Try accessing the variable through the "
"'extra' dictionary. Check the README for more information."Common Error Scenarios:
# _data/config.yaml
api:
base_url: "https://api.example.com"
version: "v1"
endpoints:
users: "/users"
posts: "/posts"Usage: {{ config.api.base_url }}
// _data/settings.json
{
"theme": {
"colors": {
"primary": "#007acc",
"secondary": "#f0f0f0"
},
"fonts": ["Arial", "Helvetica"]
}
}Usage: {{ settings.theme.colors.primary }}
Configure Jinja2 template engine delimiters and behavior:
plugins:
- markdownextradata:
jinja_options:
# Comment delimiters
comment_start_string: "/*"
comment_end_string: "*/"
# Variable delimiters
variable_start_string: "[["
variable_end_string: "]]"
# Block delimiters
block_start_string: "{%"
block_end_string: "%}"
# Undefined behavior
undefined: "jinja2.StrictUndefined"Organize data across multiple directories:
plugins:
- markdownextradata:
data: "shared/_data, project/_data, client/_data"Processing Order:
os.path.splitext(os.path.relpath(filename, ds_folder))[0]# Python version compatibility
import sys
if sys.version_info[0] >= 3:
str_type = str
else:
str_type = mkdocs.utils.string_types
# Configuration constants
CONFIG_KEYS = [
"site_name",
"site_author",
"site_url",
"repo_url",
"repo_name"
]
# Plugin class with configuration
class MarkdownExtraDataPlugin(BasePlugin):
"""MkDocs plugin for injecting extra variables into markdown templates."""
JINJA_OPTIONS = "jinja_options"
config_scheme = (
("data", mkdocs.config.config_options.Type(str_type, default=None)),
(JINJA_OPTIONS, mkdocs.config.config_options.Type(dict, default={}))
)
# Instance attributes set during plugin lifecycle
env: jinja2.Environment # Set in on_config
mkdocsConfig: mkdocs.config.Config # Set in on_config