0
# External Integration
1
2
Methods for integrating with other MkDocs plugins and external systems, including registration hooks and debugging utilities.
3
4
## Capabilities
5
6
### Plugin Registration Hooks
7
8
Methods for other MkDocs plugins to register macros, filters, and variables with the macros plugin.
9
10
```python { .api }
11
class MacrosPlugin:
12
def register_macros(self, items: dict):
13
"""
14
Register macros from external plugins.
15
16
Args:
17
items: Dictionary of {name: function} pairs
18
19
Raises:
20
KeyError: If macro name already exists
21
"""
22
23
def register_filters(self, items: dict):
24
"""
25
Register filters from external plugins.
26
27
Args:
28
items: Dictionary of {name: function} pairs
29
30
Raises:
31
KeyError: If filter name already exists
32
"""
33
34
def register_variables(self, items: dict):
35
"""
36
Register variables from external plugins.
37
38
Args:
39
items: Dictionary of {name: value} pairs
40
41
Raises:
42
KeyError: If variable name already exists
43
"""
44
```
45
46
#### Usage Examples
47
48
From another MkDocs plugin:
49
```python
50
class MyPlugin(BasePlugin):
51
def on_config(self, config):
52
# Find the macros plugin
53
for plugin in config.plugins:
54
if hasattr(plugin, 'register_macros'):
55
# Register our functions
56
plugin.register_macros({
57
'my_custom_macro': self.my_macro_function,
58
'another_macro': lambda x: f"Processed: {x}"
59
})
60
61
plugin.register_filters({
62
'my_filter': self.my_filter_function
63
})
64
65
plugin.register_variables({
66
'plugin_version': '1.0.0',
67
'plugin_config': self.config
68
})
69
break
70
71
def my_macro_function(self, text):
72
return f"<span class='highlight'>{text}</span>"
73
74
def my_filter_function(self, value):
75
return str(value).replace(' ', '_')
76
```
77
78
Standalone registration utility:
79
```python
80
def register_with_macros(config, macros_dict, filters_dict=None, variables_dict=None):
81
"""Utility to register items with macros plugin"""
82
for plugin in config.plugins:
83
if hasattr(plugin, 'register_macros'):
84
if macros_dict:
85
plugin.register_macros(macros_dict)
86
if filters_dict:
87
plugin.register_filters(filters_dict)
88
if variables_dict:
89
plugin.register_variables(variables_dict)
90
return True
91
return False
92
```
93
94
### Debug and Logging Utilities
95
96
Methods for creating debug output and logging functionality within macros.
97
98
```python { .api }
99
class MacrosPlugin:
100
def start_chatting(self, prefix: str, color: str = 'yellow') -> callable:
101
"""
102
Create a debug function for verbose output.
103
104
Args:
105
prefix: Module/component name for log messages
106
color: Color for terminal output ('yellow', 'green', 'red', etc.)
107
108
Returns:
109
Chatter function that logs messages when verbose mode is enabled
110
"""
111
```
112
113
#### Usage Examples
114
115
Module with debug output:
116
```python
117
def define_env(env):
118
# Create debug function
119
chatter = env.start_chatting('MY_MODULE', 'green')
120
121
chatter("Module initialization started")
122
123
@env.macro
124
def debug_macro(value):
125
chatter(f"Processing value: {value}")
126
result = str(value).upper()
127
chatter(f"Result: {result}")
128
return result
129
130
chatter("Module loaded successfully")
131
```
132
133
Conditional debugging:
134
```python
135
def define_env(env):
136
chatter = env.start_chatting('DATA_PROCESSOR')
137
138
@env.macro
139
def process_data(data_list):
140
chatter(f"Processing {len(data_list)} items")
141
142
results = []
143
for i, item in enumerate(data_list):
144
chatter(f"Processing item {i}: {item}")
145
processed = item.upper().strip()
146
results.append(processed)
147
148
chatter(f"Completed processing, {len(results)} results")
149
return results
150
```
151
152
Multi-level debugging:
153
```python
154
def define_env(env):
155
# Different debug levels with colors
156
info = env.start_chatting('INFO', 'blue')
157
warn = env.start_chatting('WARN', 'yellow')
158
error = env.start_chatting('ERROR', 'red')
159
160
@env.macro
161
def safe_operation(value):
162
info("Starting safe operation")
163
164
if not value:
165
warn("Empty value provided")
166
return "N/A"
167
168
try:
169
result = complex_processing(value)
170
info(f"Operation successful: {result}")
171
return result
172
except Exception as e:
173
error(f"Operation failed: {e}")
174
return "Error"
175
```
176
177
### Path and File Utilities
178
179
Methods for working with file paths and determining rendering behavior.
180
181
```python { .api }
182
class MacrosPlugin:
183
def force_page_rendering(self, filename: str) -> bool:
184
"""
185
Check if page should be force-rendered based on configuration.
186
187
Args:
188
filename: Page filename relative to docs directory
189
190
Returns:
191
True if page matches force_render_paths patterns
192
"""
193
```
194
195
#### Usage Examples
196
197
Conditional processing in hooks:
198
```python
199
def on_pre_page_macros(env):
200
"""Apply different processing based on file patterns"""
201
202
current_file = env.page.file.src_path
203
204
# Check force rendering patterns
205
if env.force_page_rendering(current_file):
206
env.variables['force_rendered'] = True
207
# Apply special processing for forced files
208
env.markdown = "<!-- Force rendered -->\n" + env.markdown
209
210
# Different processing for different file types
211
if current_file.endswith('.api.md'):
212
env.variables['is_api_doc'] = True
213
elif current_file.startswith('examples/'):
214
env.variables['is_example'] = True
215
```
216
217
File-based configuration:
218
```python
219
def define_env(env):
220
@env.macro
221
def include_if_forced(filename, content):
222
"""Only include content if file would be force-rendered"""
223
if env.force_page_rendering(filename):
224
return content
225
return ""
226
227
@env.macro
228
def get_render_status(filename):
229
"""Get rendering status for debugging"""
230
if env.force_page_rendering(filename):
231
return "Force rendered"
232
elif env.config['render_by_default']:
233
return "Default rendered"
234
else:
235
return "Opt-in only"
236
```
237
238
## Integration Patterns
239
240
### Plugin Communication
241
242
```python
243
# In another plugin
244
class MyPlugin(BasePlugin):
245
def on_config(self, config):
246
# Store reference to macros plugin
247
self.macros_plugin = None
248
for plugin in config.plugins:
249
if hasattr(plugin, 'register_macros'):
250
self.macros_plugin = plugin
251
break
252
253
def on_page_markdown(self, markdown, page, config, files):
254
# Use macros plugin for rendering
255
if self.macros_plugin:
256
# Add custom variables for this page
257
self.macros_plugin.register_variables({
258
'current_plugin': 'MyPlugin',
259
'processing_time': datetime.now()
260
})
261
```
262
263
### Shared Functionality
264
265
```python
266
# Shared utility functions for multiple plugins
267
def create_shared_macros():
268
"""Create macros that multiple plugins can use"""
269
270
def format_code(code, language='python'):
271
return f"```{language}\n{code}\n```"
272
273
def create_alert(message, type='info'):
274
return f"!!! {type}\n {message}"
275
276
def embed_youtube(video_id):
277
return f'<iframe src="https://youtube.com/embed/{video_id}"></iframe>'
278
279
return {
280
'format_code': format_code,
281
'alert': create_alert,
282
'youtube': embed_youtube
283
}
284
285
# Register from multiple plugins
286
def register_shared_functionality(config):
287
shared_macros = create_shared_macros()
288
289
for plugin in config.plugins:
290
if hasattr(plugin, 'register_macros'):
291
plugin.register_macros(shared_macros)
292
break
293
```
294
295
### Configuration Integration
296
297
```python
298
class IntegratedPlugin(BasePlugin):
299
config_scheme = (
300
('enable_macros', Type(bool, default=True)),
301
('macro_prefix', Type(str, default='plugin')),
302
)
303
304
def on_config(self, config):
305
if not self.config['enable_macros']:
306
return
307
308
# Find and configure macros plugin
309
for plugin in config.plugins:
310
if hasattr(plugin, 'register_macros'):
311
prefix = self.config['macro_prefix']
312
313
plugin.register_macros({
314
f'{prefix}_function': self.my_function,
315
f'{prefix}_utility': self.utility_function
316
})
317
318
plugin.register_variables({
319
f'{prefix}_config': dict(self.config),
320
f'{prefix}_enabled': True
321
})
322
break
323
```
324
325
## Error Handling
326
327
### Registration Conflicts
328
329
```python
330
def safe_register_macros(plugin, macros_dict):
331
"""Safely register macros with conflict handling"""
332
for name, func in macros_dict.items():
333
try:
334
plugin.register_macros({name: func})
335
except KeyError as e:
336
print(f"Warning: Macro {name} already exists: {e}")
337
# Try with prefixed name
338
prefixed_name = f"ext_{name}"
339
try:
340
plugin.register_macros({prefixed_name: func})
341
print(f"Registered as {prefixed_name} instead")
342
except KeyError:
343
print(f"Could not register {name} even with prefix")
344
```
345
346
### Plugin Detection
347
348
```python
349
def find_macros_plugin(config):
350
"""Find macros plugin in configuration"""
351
for plugin in config.plugins:
352
if hasattr(plugin, 'register_macros'):
353
return plugin
354
return None
355
356
def ensure_macros_plugin(config):
357
"""Ensure macros plugin is available"""
358
plugin = find_macros_plugin(config)
359
if not plugin:
360
raise RuntimeError("MkDocs Macros plugin not found in configuration")
361
return plugin
362
```
363
364
## Best Practices
365
366
1. **Check plugin availability** before attempting registration
367
2. **Handle registration conflicts** gracefully with prefixes or warnings
368
3. **Use descriptive prefixes** for external functions to avoid naming conflicts
369
4. **Document integration requirements** in your plugin documentation
370
5. **Test with different plugin load orders** to ensure compatibility
371
6. **Use debug output** to track registration and execution
372
7. **Provide fallbacks** when macros plugin is not available