Closed honzajavorek closed 3 years ago
In principle variables created are to be used in the markdown files.
You can of course create variables from within the python module. The most intuitive way is by adding entries in the env.variables
dictionary (see more on this).
Mkdoc's HTML templates are another thing (it's a completely distinct jinja2 engine, which comes out of the box with mkdocs). This templating engine uses the metadata of the markdown page to enrich the HTML code generated.
You can, however, use the python module to create or update page metadata by updating the enva.page.meta
dictionary.
Caution: This cannot be done with the standard define_env()
function, since that function is executed at a time of the building process, where the pages have not been generated yet (and the page
variable is not available yet).
The proper way to generate metadata is described in a specific paragraph.. There are two functions, on_pre_page_macros()
and on_post_page_macros()
which have access (at a later stage) to the env.page.meta
dictionary. It's not particularly difficult to do.
You can perfectly share information between define_env()
and these other functions, typically through Python variables that are global to the module.
That would be the general way to trickle information from the macro environment to the jinja2/HTML template.
Let me know if this helps?
Thank you, reading your response, it sounds exactly like what I'm looking for. I learned the mechanics you're writing about in the docs, but I guess I was missing the page.meta
piece as to what's the most appropriate place where to put the vars. I'll return and report back in a few days, after I try it out. At this point I think I have all the info I needed 👍
Thank you. I'm pleased when someone tells me I have provided the type of answer that they expected. 😄
So I got back to this and am experimenting with what we discussed. I didn't want my main project's specifics to interfere with this particular issue, so I created this playground sample project from scratch:
https://github.com/honzajavorek/mkdocs-macros-playground
It's a minimal example with just one document and a very simple template. At the time of writing this comment I couldn't get it work with modifying page.meta
in the on_...()
function:
The current code of main.py
is:
def define_env(env):
env.variables['content_variable'] = 'works!'
def on_pre_page_macros(env):
env.page.meta['content_and_template_variable'] = 'works!'
I'll keep experimenting and if I come up with a solution or have a progress, I'll report back here. You can browse the repo to see the context and all other files. Any ideas how to get it work would be highly appreciated.
Okay, I played around with it and figured it out! One mistake I was doing was expecting the template will have the variables set just under their names, but they need to be extracted from the config and page data structures. To my current knowledge, one can dynamically (in Python code) set a variable to both the Markdown content and the theme template in at least two ways:
Both are demonstrated in the earlier mentioned repo I created exactly for this purpose. It generates the following page:
For future reference, I'll share the bits of code here, too:
dynamic_extra_var = 'works!'
def define_env(env):
env.variables['dynamic_extra_var'] = dynamic_extra_var
env.variables['dynamic_macros_var'] = 'works!'
def on_pre_page_macros(env):
env.conf['extra']['dynamic_extra_var'] = dynamic_extra_var
env.page.meta['dynamic_meta_var'] = 'works!'
Modifying extra only works for the theme, so the same variable needs to be sent to macros again in a standard way. Maybe there's an order of assignments, which would prevent this, but I didn't experiment further to verify. Compared to this, meta is sufficient to modify only once, so that approach seems like a better way to go.
In the document, variables can be referenced directly by their names:
---
static_meta_var: 'works!'
---
# Magnificent Title
This is in the Markdown content enhanced with the Macros plugin. Static means it can be edited by human in a file:
- Printing `static_extra_var`: {{ static_extra_var }}
- Printing `static_meta_var`: {{ static_meta_var }}
Dynamic means it's set by a Python code:
- Printing `dynamic_macros_var`: {{ dynamic_macros_var }}
- Printing `dynamic_extra_var`: {{ dynamic_extra_var }}
- Printing `dynamic_meta_var`: {{ dynamic_meta_var }}
In the theme, variables need to be extracted from the config and page objects:
{{ page.title }}
<hr>
{{ page.content }}
<hr>
<p>
Now this is in the theme template, that means MkDocs's very own Jinja2.
</p>
<ul>
<li>Printing <code>static_extra_var</code>: {{ config.extra.static_extra_var|default('DOES NOT WORK') }}</li>
<li>Printing <code>static_meta_var</code>: {{ page.meta.static_meta_var|default('DOES NOT WORK') }}</li>
<li>Printing <code>dynamic_extra_var</code>: {{ config.extra.dynamic_extra_var|default('DOES NOT WORK') }}</li>
<li>Printing <code>dynamic_meta_var</code>: {{ page.meta.dynamic_meta_var|default('DOES NOT WORK') }}</li>
</ul>
I've read through all the docs, but I'm still unclear about one thing and any guidance would be very appreciated. Let's say I want to dynamically declare a variable, which would be accessible in both the macros and the MkDocs' Jinja2, because I want to use it in the HTML template of the theme, too. Normally, this would be set in
extras:
in the YAML config, I suppose, but as it's dynamic, it cannot be. As an example, I'll choosenow
.The
now
is available out of the box with macros, that's nice. But let's say I want to use it in headers or footers, too, in my theme. Can I use macros to (re)define it somehow so it's available even there? I tried to modifyenv.conf
,env.variables
etc., but it seems "it's too late" at that moment. If I was writing my own plugin, I'd do something like this:Such variables would trickle down to both the theme and the pages/macros. At least I think. What would be the correct way to do this in macros, so that I don't need to introduce my own plugin? Thanks!