Closed squidfunk closed 8 months ago
I have a few tags set up for the usual tag things (public-facing organisation of similar things). But I also have a set of tags that I only use for organisation, kind of like what you describe. Let me explain:
plugins:
- file-filter:
enabled_on_serve: false
exclude_tag: ["internal", "draft", "braindump", "placeholder"]
this way, I can work on articles well in advance. I tag them with internal
(long-term storage of information just for myself), draft
(something nearly finished, usually the thing I am currently working on), braindump
(stuff I will work on later where I currently just note stuff in a rather unstructured way to get them out of my head) and placeholder
(something I might take up at some point, but that basically just serves as an empty reminder file, often while structuring whole chapters).
tag_decorator
: based on the tags mentioned above, it will augment the navigation entries with simple emoji. This state will also propagate up the navigation tree, so I can see on the top level which sub-level has anything to work on. This has one further function which also modifies based on file modification, but that's not tied to tags.weight_decorator
adds the weight
frontmatter property that mkdocs-nav-weight uses to the navigation entries.together, they give me a nav tree like this, all emoji and numbers you see here are added automatically. None of this shows up in production (in fact, half of the articles pictured here are still being written and don't show up in production at all. Only the :heavy_check_mark: articles go live).
@Guts, thought you should be aware of this and we should think about how this might impact the RSS plugin. Could open up some new opportunities? Anything (more) from your side / the side of users of the RSS plugin to help shape this functionality?
I would love to see support for "nested tags"/"hierarchical tags", similar to what was requested in https://github.com/squidfunk/mkdocs-material/issues/4839
My source content has this format:
---
tags:
- foo/pippo
---
# Some Page
[...]
---
tags:
- foo/pluto
---
# Another Page
[...]
Currently, this results in a tag index structure like:
The intention is a structure like this:
This slash-separated nested tag format (which was specified in https://github.com/squidfunk/mkdocs-material/issues/4839) is an established convention. Examples of where it is already in use:
What happens if I use the tags foo
, foo/pluto
and pluto
? How do they relate? Are hierarchical tags a tree or a graph, i.e., are relations uni- or bidirectional?
In Obsidian, something that is tagged #foo/pluto
gets found by a search for #foo
but not when I search for #pluto
(there is one page tagged with only #pluto
). Consequently, there is a tag tree in the UI:
Obsidian also has a graph view for the pages. When I filter for #foo
, I get this:
The green dots are the tags and the white ones the pages that contain them. You can see that here a distinction is made between #foo
and #foo/pluto
. There is no connection between the two tags, which I find a bit surprising.
Thanks for the clarification! Creating this issue already paid off by collecting additional use cases. We'll see how we can make nested tags work. IMHO, there should definitely be a relation, but I agree that it should be trees, as we already have the tags graph itself.
@Guts, thought you should be aware of this and we should think about how this might impact the RSS plugin. Could open up some new opportunities? Anything (more) from your side / the side of users of the RSS plugin to help shape this functionality?
Thanks for the ping @alexvoss!
On the RSS plugin side, we mainly refer to the YAML frontmatter (mkdocs.page.meta
) to define the feed items categories as defined in RSS specification. User has to specify in categories
option which YAML key/s the plugin should use as item's keywords/tags/category (default to None).
See the related section in plugin's documentation: https://guts.github.io/mkdocs-rss-plugin/configuration/#categories-item-categories
On the Material theme side, the documentation make some recomendations about how to use this option (https://squidfunk.github.io/mkdocs-material/setup/setting-up-a-blog/#rss) by defining tags
and categories
To sum up: for now there is no direct relationship between Material tags plugin and RSS plugin.
I second @Guts – the RSS plugin and the tags plugin are two plugins that both consume front matter properties, but for different purposes.
Now, if I put aside my role as the main developer and maintainer of the RSS plugin, I find these evolutions exciting. On the whole, I always find the design or refactoring phases, or the major evolution of bricks that are already widely used, really interesting.
Tags is typically a common feature hiding huge stakes for end-user experience.
Every innovation mentioned in the description seems very good to me. If I have to say something to challenge the collective idéation:
@Guts, it might matter to you how the hierarchical tags are implemented. The RSS standard defines them as slash-separated.
Hierarchical tags will be an implementation detail of the tags plugin. As long as the RSS plugin consumes tags from metadata and not from the tags plugin instance, it doesn't matter how hierarchical tags are implemented. If it decides to consume them from the tags plugin, this is of course different, but I think this doesn't make sense to do.
Now, if I put aside my role as the main developer and maintainer of the RSS plugin, I find these evolutions exciting. On the whole, I always find the design or refactoring phases, or the major evolution of bricks that are already widely used, really interesting.
We will put significant effort in making the transitioning phase as simple as possible. Hierarchical tags will be opt-in, the separator will be configurable (defaulting to /
). The obsolete tags_file
and tags_extra_files
(now replaced with inline comments) will receive proper deprecation paths and continue to work until the next major version. We'll also make sure that the tags plugin works the same between the community version and Insiders.
I'm a big fan of semantic web and I would like to see more of schemas to be automatically generated in documentation websites. Here, why not about the keywords or DefinedTerm?
Could you expand on this a little? Should the tags plugin generate a schema for the concrete tags used by the author, or how would you imagine this to work?
why not propose an old-school words cloud? or something approaching. I've recently started something with wordcloud and a mask inspired from the graphical elements of the website (in the spirit of social cards). Was "just for the fun"; now I'm questioning myself if it would land on the homepage 😅. Seriously, with the mentioned tags.json file, it would be really easier to make some things like this :).
That's essentially just another rendering of a tags index and will definitely be possible to pull off with the new architecture. We might provide a default renderer for this as well. tags.json
will definitely be a part of the new plugin.
Hierarchical tags will be an implementation detail of the tags plugin.
They are not hidden, though. The way they are done will filter through to the RSS feed via mkdocs-rss-plugin
. Slashes by default are good in that respect.
Configurable is also good, though perhaps it might be good to mention that using things other than slashes could break some RSS-reader behaviour? That is, if RSS-readers are doing anything meaningful with the categories - I just checked mine (Reeder) and it does not seem to, which is a bit surprising and disappointing. Does anyone know a reader that allows filtering/grouping by the RSS category?
We're still in ideation and prototyping phase, once we have everything ready, we should check what we should document, but currently it'd be premature documentation (cough) ☺️
Does anyone know a reader that allows filtering/grouping by the RSS category?
Thunderbird?
Progress! Here's a quick demo of what you'll be able to do in the coming days:
mkdocs.yml
https://github.com/squidfunk/mkdocs-material/assets/932156/bf71d694-8a10-4135-b79c-a6f4d20db8e8
Define listing using inline syntax:
<!-- material/tags { include: [foo/a, foo/b], scope: true } -->
Define listing using block syntax:
<!--
material/tags
include:
- foo/a,
- foo/b
scope: true
-->
Reference a pre-defined listing:
<!-- material/tags bar -->
This makes tags much more flexible already, as you can now allow your users to "hop" through your documentation by cleverly chaining tags indexes. I'm still working on the other things described in my OP, and need to clean up the mess I made – so many levels of indirections, so I'll need a few days still, but I love how this is turning out.
I'll post here when I got a first clean draft in Insiders which you can install and play with on your machine ☺️ Those of you who're not sponsors yet: you can support the project and make this feature happen faster by sponsoring @squidfunk! Additionally, you can build this feature with us, together, influencing precisely how it will turn out in the end!
@squidfunk - cannot watch the video?
Weird – does the one on Twitter work (it's the same)? https://twitter.com/squidfunk/status/1736761608666255866
Yes, it does. A MIME type issue rather than an encoding one? This is on a Mac and on Linux - aha, the common factor here is Firefox. Safari works fine on the Mac.
Not sure why this is the case. I need to improve my screen recording setup.
Did you replace the video? Because now I closed the tab and came back to it after a while - the video is working, same browser. Perhaps GitHub re-encodes uploaded videos and the pipeline took a bit of time? In any case, seems fine now.
And I just finished a first prototype of the hierarchical renderings of the tags index. It's not beautiful, yet, but we're getting there. I'm first focusing on functionality and we'll improve the styling once we got it working:
Pages are tagged as follow:
[bar/a, bar/a]
[bar, bar/b]
This shows the following properties:
I still need to clean up all the mess I made, hope to finish the prototype today or tomorrow!
Next update: shadow tags. Now, tags can be hidden when rendering listings and pages, but they will still exist in the tags structure and be marked as hidden. This allows for creating listings that are solely meant for temporary collecting and tagging pages or blog posts (e.g. for todos). In this example, tags starting with _
are marked as shadow tags:
Tags can be marked as shadow tags by adding them to the explicit shadow_tags
list, or by prefix or suffix. Same as for the blog post draft
state, tags can be rendered during mkdocs serve
and removed during mkdocs build
. In the screenshot above, they're rendered during mkdocs serve
.
And the first version is available! https://github.com/squidfunk/mkdocs-material-insiders/pull/76
The PR implements almost all of the features proposed in my OP. I've adjusted the OP with check lists what is already implemented. I've also opened a PR on our examples repository demonstrating the three greatest new features: scoped listings, tag hierarchies and shadow tags.
No more tags_file
and tags_extra_files
settings (will be kept for downward compatibility, of course) – using the tags plugin is now much, much easier and much more flexible. You can render listings (= tags indexes) anywhere.
I recommend to check out the examples. As a quick idea, here's the new annotated configuration of the plugin – most settings are quite self explanatory. All commented settings are new. I'll add documentation in the coming days, but the brave of you can already give it a spin:
class TagsConfig(Config):
enabled = Type(bool, default = True)
# Settings for filtering
filters = SubConfig(FilterConfig)
# Settings for tags
tags = Type(bool, default = True)
tags_slugify = Type(Callable, default = slugify(case = "lower"))
tags_slugify_separator = Type(str, default = "-")
tags_slugify_format = Type(str, default = "tag:{slug}") # slug is now passed through this format string
tags_hierarchy = Type(bool, default = False) # hierarchical tags are disabled by default
tags_hierarchy_separator = Type(str, default = "/") # you can configure the hierarchy separator
tags_sort_by = Type(Callable, default = tag_name)
tags_sort_reverse = Type(bool, default = False)
tags_name_property = Type(str, default = "tags") # name of the front matter property in Markdown
tags_name_variable = Type(str, default = "tags") # name of the template variable for tags in pages
tags_allowed = TagSet()
# Settings for listings
listings = Type(bool, default = True) # whether listings should be rendered (= tag indexes)
listings_map = DictOfItems(SubConfig(ListingConfig), default = {}) # pre-defined listings
listings_sort_by = Type(Callable, default = item_title) # sort function for pages under a tag
listings_sort_reverse = Type(bool, default = False)
listings_tags_sort_by = Type(Callable, default = tag_name) # sort function for tags in listings
listings_tags_sort_reverse = Type(bool, default = False)
# Settings for shadow tags
shadow = Type(bool, default = False) # whether to render shadow tags or remove them
shadow_on_serve = Type(bool, default = True) # when serving, enabled rendering of shadow tags
shadow_tags = TagSet() # these tags should be considered shadow tags
shadow_tags_prefix = Type(str, default = "") # tags starting with this string are shadow tags
shadow_tags_suffix = Type(str, default = "") # tags ending with this string are shadow tags
I'm so happy how this turned out – the tags plugin is infinitely more powerful and I can't wait what use cases we can solve with this beast. I've wanted to give the tags plugin a rewrite for a year now, and @alexvoss motivated me to give it a go. Our examples repository will host a pretty complex and comprehensive tags index, so this is definitely use case no 0.
The new tags plugin was released as part of 9.5.3+insiders-4.48.0. This is a HUGE release 🥳
We'll keep this issue open until we finished to update our documentation. We want to provide more use cases and case studies how the new tags plugin can help you, so quite some stuff to write, but the brave of you can already give it a spin 🚀 It should be downward compatible, albeit print warning messages if you're using tags_file
and tags_extra_files
– those are now deprecated and no longer necessary. Just use the inline syntax as mentioned in https://github.com/squidfunk/mkdocs-material/issues/6517#issuecomment-1860689219
This took significant effort, but the result is just wow. The tags plugin was the first plugin that I wrote several years ago, and it was quite dated. The capabilities now are on a whole new level. In fact, I know of no other SSGs that have such a powerful tags plugin, allowing you to place customizable listings basically everywhere. It should now also align more nicely with the capabilities of Obsidian.
All of this was only made possible by our awesome sponsors ❤️ Sponsorships are allowing me to push this project further and further, creating one of the simplest yet most powerful frameworks for writing documentation.
Documentation was added in https://github.com/squidfunk/mkdocs-material/commit/fee72372fb9f7a209f18f11c56fc1447cf68843d.
The documentation barely touches what the new plugin is capable of. We will use the tags plugin as the first patient for restructuring our setup guide into usage-centric guides with examples and starter templates. A first draft for a structure with some diagrams is in #6556. I imagine that we create a new section that evolves around the topic of structuring a documentation project with Material for MkDocs. This section should accompany our users on their journey from starting out with a single Markdown file up to several thousand files. This includes the usage of the following features and plugins:
navigation.*
featurestoc.*
featuresWe'll continue to work on this in #6556.
I'm closing this issue for now. In the coming weeks, we add more examples and better documentation on the plugin, so users can better understand what can now be done with it. Since this will be part of a much larger rewrite, it doesn't make sense to keep this open, as there's already a lot of information packed in this issue, which will be distilled into better documentation.
If you have feedback on the new plugin, you can post it here.
Hello everyone,
We're currently rethinking the tags plugin, transforming it into something much more powerful with the help of your feedback. Here's a sneak peek into the progress we've made and the innovations on the horizon:
[x] Inline Tag Indexes: Introducing a new feature where you can integrate tag indexes directly within your Markdown content. By simply adding an inline comment like
<!-- material/tags -->
, you can create a dynamic tag index within any page, offering unprecedented flexibility in how and where tags are displayed.[x] Context-Aware Tag Rendering: The plugin will intelligently render tags based on their context. For instance, if a tag index is placed below an
h3
heading in your Markdown file, the tags will appear withh4
styling. This ensures that the tag index naturally fits into the structure of your document, maintaining both readability and aesthetic appeal.[x] Shadow Tags for Cleaner Presentations: Some tags might be necessary for organization but not ideal for display. We're looking to introduce functionality to mark certain tags as hidden. These tags can be used for internal structuring without cluttering your page, keeping the focus on the content that matters most to your readers.
[x] Enhanced Flexibility with Customizable Front Matter Properties: The plugin will support customizable front matter properties. This means you can run multiple instances of the tags plugin with different configurations simultaneously, allowing for more complex and nuanced tagging systems, e.g., using
tags
andcategories
alongside each other.[x] Scoped Tag Listings for Large Documentations: For extensive documentation, we plan to implement a scoped mode where a tags index includes only the pages under a specific section. This feature will enable you to create specialized tags indexes for different subsections easily, improving navigation in large document sets.
[x] Declarative Tag Collections in
mkdocs.yml
: You'll be able to define named collections of tags directly in yourmkdocs.yml
. This feature will enable you to group tags declaratively, and these collections can then be referenced in Markdown files, combining them with other features like scope for more precise control.[x] Hierarchical Tags: The plugin should allow to define nested tags, i.e.,
foo
andfoo/bar
in order to build trees of tags.[x] Custom Templates for Different Index Types: Recognizing that one size does not fit all, we plan to allow users to define custom templates for different types of tag indexes. This means you could have a visually distinct layout for a blog post overview compared to a regular index of pages, enhancing the visual hierarchy and user navigation.
Coming very soon
tags.json
index, which can be consumed by other plugins. This opens the door for aggregating tags across different projects, fostering a more interconnected documentation ecosystem.These enhancements aim to transform the tags plugin into a more powerful, flexible, and user-friendly tool, enhancing the overall documentation experience on MkDocs. We're excited to see how these features will be utilized to create more dynamic and interconnected content. Your feedback and ideas are always welcome as we continue to improve the MkDocs ecosystem.
Feel free to share anything that's on your mind.