Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

🏷️ Tags plugin 2.0 – now available #6517

Closed
8 tasks done
squidfunk opened this issue Dec 17, 2023 · 26 comments
Closed
8 tasks done

🏷️ Tags plugin 2.0 – now available #6517

squidfunk opened this issue Dec 17, 2023 · 26 comments
Labels
announcement Issue announces news or new features

Comments

@squidfunk
Copy link
Owner

squidfunk commented Dec 17, 2023

Note

The new tags plugin is available as of 9.5.3+insiders-4.48.0

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:

  • 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.

  • 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 with h4 styling. This ensures that the tag index naturally fits into the structure of your document, maintaining both readability and aesthetic appeal.

  • 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.

  • 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 and categories alongside each other.

  • 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.

  • Declarative Tag Collections in mkdocs.yml: You'll be able to define named collections of tags directly in your mkdocs.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.

  • Hierarchical Tags: The plugin should allow to define nested tags, i.e., foo and foo/bar in order to build trees of tags.

  • 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

  • Specialized Tag Index Syntax for Blogs and More: We're adding additional shortcode options that cater to specific types of content, such as blog posts. This could include functionality like showcasing the "most recent 3 blog posts" or generating a list of "suggested pages" based on tags, providing a more tailored and engaging user experience.
  • Cross-Project Tag Integration: The plugin is set to emit a 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.

@ccoenen
Copy link

ccoenen commented Dec 17, 2023

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:

  • I use the file filter plugin and I configured it like this:
    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).
  • I have two additional hooks that only run in development mode:
    • 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 ✔️ articles go live).
internal development nav tree of fediverse.jetzt

@alexvoss
Copy link
Sponsor Collaborator

@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?

@per1234
Copy link
Sponsor

per1234 commented Dec 17, 2023

I would love to see support for "nested tags"/"hierarchical tags", similar to what was requested in #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:

  • foo/pippo
    • Some Page
  • foo/pluto
    • Another Page

The intention is a structure like this:

  • foo
    • pippo
      • Some Page
    • pluto
      • Another Page

This slash-separated nested tag format (which was specified in #4839) is an established convention. Examples of where it is already in use:

@squidfunk
Copy link
Owner Author

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?

@alexvoss
Copy link
Sponsor Collaborator

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:

image

Obsidian also has a graph view for the pages. When I filter for #foo, I get this:

image

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.

@squidfunk
Copy link
Owner Author

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
Copy link
Contributor

Guts commented Dec 17, 2023

@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.

@squidfunk
Copy link
Owner Author

I second @Guts – the RSS plugin and the tags plugin are two plugins that both consume front matter properties, but for different purposes.

@Guts
Copy link
Contributor

Guts commented Dec 17, 2023

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:

  • 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?
  • for nested tags, I've recently used the GitLab labels and more specifically the scoped labels and I have to say that I like it. Idea, UI and usage (filter/search).
  • 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 :).

@alexvoss
Copy link
Sponsor Collaborator

@Guts, it might matter to you how the hierarchical tags are implemented. The RSS standard defines them as slash-separated.

@squidfunk
Copy link
Owner Author

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.

@alexvoss
Copy link
Sponsor Collaborator

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?

@squidfunk
Copy link
Owner Author

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) ☺️

@Guts
Copy link
Contributor

Guts commented Dec 17, 2023

Does anyone know a reader that allows filtering/grouping by the RSS category?

Thunderbird?

@squidfunk
Copy link
Owner Author

squidfunk commented Dec 18, 2023

Progress! Here's a quick demo of what you'll be able to do in the coming days:

  • Define tags indexes on any page
  • Configure specifically which tags are rendered
  • Define inclusion and exclusion lists for indexes
  • Scope tags index to the current subtree
  • Build hierarchical indexes (see video)
  • Use pre-defined listings from mkdocs.yml
  • Use inline listings for micro-indexes
  • Tags are automatically linked to the closest index
  • Tags that are not referenced in indexes are not linked
Ohne.Titel.mov

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!

@alexvoss

This comment was marked as outdated.

@squidfunk

This comment was marked as outdated.

@alexvoss

This comment was marked as outdated.

@squidfunk

This comment was marked as outdated.

@alexvoss

This comment was marked as outdated.

@squidfunk
Copy link
Owner Author

squidfunk commented Dec 19, 2023

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:

Bildschirm­foto 2023-12-19 um 13 43 09

Pages are tagged as follow:

  • Bar A: [bar/a, bar/a]
  • Bar B: [bar, bar/b]

This shows the following properties:

  • Repeated tags are ignored, so that each page is always only tagged with a single tag. This makes interop with the meta plugin much simpler, as you can be sure that each page only receives a tag once.
  • Pages are only listed in the parent of a tag if they are explicitly tagged with the parent tag. AFAIU, this is in line with what other nested tag solutions do. If there's a use case where tags need to be propagated, also no problem.

I still need to clean up all the mess I made, hope to finish the prototype today or tomorrow!

@squidfunk
Copy link
Owner Author

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:

Bildschirm­foto 2023-12-21 um 12 34 10

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.

@squidfunk
Copy link
Owner Author

squidfunk commented Dec 22, 2023

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.

@squidfunk squidfunk changed the title Rethinking the tags plugin 🏷️ Tags plugin 2.0 – now available Dec 22, 2023
@squidfunk
Copy link
Owner Author

squidfunk commented Dec 23, 2023

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 #6517 (comment)

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.

@squidfunk
Copy link
Owner Author

Documentation was added in fee7237.

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:

  • The navigation.* features
  • The toc.* features
  • The tags plugin
  • The projects plugin
  • The meta plugin
  • Possibly other plugins that work with Material for MkDocs (awesome pages? mkdocstrings?)

We'll continue to work on this in #6556.

@squidfunk
Copy link
Owner Author

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.

@squidfunk squidfunk unpinned this issue Jan 7, 2024
Guts added a commit to geotribu/website that referenced this issue Jan 14, 2024
Le plugin de gestion des mots-clés a subi une refonte qui implique de
nombreux changements
(squidfunk/mkdocs-material#6517). Cette PR
intègre les modifications nécessaires.

De plus, j'ai enfin trouvé le bug qui fait péter pas mal d'icônes de
tags : squidfunk/mkdocs-material#6635. Vu que
l'ordre est significatif, j'ai désactivé le tri automatique du YAML en
sortie.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
announcement Issue announces news or new features
Projects
None yet
Development

No branches or pull requests

5 participants