Skip to main content

Lektor plugin to add tags.

Project description

Lektor Tags Plugin

PyPI version Code style: black


This plugin implements tagging for your site. For each of your tags, it builds a page displaying a list of items that have that tag. This can be used for standard tag-based blog navigation. With this plugin you can give any number of tags to any blog posts, and a page will be created for each tag.

For example, if your site has blog posts in your content/blog directory tagged with coffee and tea:

name: First Post


The lektor-tags plugin builds pages at these URLs:

  • /blog/tag/coffee/
  • /blog/tag/tea/

Each page can list all the posts with that tag.


Add lektor-tags to your project from command line:

lektor plugins add lektor-tags

See the Lektor documentation for more instructions on installing plugins.


Say you have a "blog-post" model like this:

name = Blog Post

type = strings

Make a blog-post.html template that includes:

{% if this.tags %}
    {% for t in this.tags -%}
        <a href="{{ ('/blog@tag/' ~ t.lower())|url }}">
          All posts tagged {{ t }}
    {% endfor %}
{% endif %}

This expression in the template generates a source path for each of the blog post's tags:

'/blog@tag/' ~ t.lower()

Then if the tag is "my-tag", the expression renders a source path like:


A Lektor source path becomes an actual URL using the url filter. So the template generates URLs to tag pages like:

<a href="{{ ('/blog@tag/' ~ t.lower())|url }}"></a>

This uses the source path expression from before, but pipes it through url to generate an actual link from the blog post to a tag page.


Set these options in configs/tags.ini:


Required. The source path of the tag pages' parent page. For example:

parent = /blog

Then tag pages' source paths are like:


You can specify the root as the parent:

parent = /


A query for all items on the page for one tag. You can use the variables site and tag. The template's this variable has a parent attribute. The default query is:

items = this.parent.children.filter(F.tags.contains(tag))

You can sort and filter with any expression:

items = this.parent.children.filter(F.tags.contains(tag) and F.status == 'published').order_by('-pub_date')

If the parent page has a pagination query you may want to use it for tagged pages:

items = this.parent.pagination.items.filter(F.tags.contains(tag))

See the Lektor documentation for queries.


The name of the field in your model that contains tags. Defaults to tags. The field should be of type strings. See the Lektor documentation for the strings type.

For example, if your model is like:

type = strings

Then add this to tags.ini:

tags_field = labels


The template for the page that lists all posts with a certain tag. The template's this variable has attributes tag and items. An example template:

<h1>Tag: {{ this.tag }}</h1>
  {% for i in this.items %}
    <li><a href="{{ i|url }}">{{ i._id }}</a></li>
  {% else %}
    <li><em>No items.</em></li>
  {% endfor %}

Save a file like this to your project's templates/tags.html. If you name the file something different, like label.html, add this line to tags.ini:

template = label.html

The plugin provides a default template if you don't specify one.


An expression for the location of each tag page. You can use the variables site and tag. The this variable is a page with attributes parent and items. The default expression is:

url_path = {{ this.parent.url_path }}tag/{{ tag }}

This expression generates URLs like /blog/tag/coffee.


Default false. To set true, add this line to tags.ini:

ignore_missing = true

This allows URLs to missing tag pages to be silently replaced with "". The example use case is if your blog-post.html template includes a statement like:

{% for t in this.tags -%}
  <a href="{{ ('/blog@tag/' ~ t.lower())|url }}">{{ t }}</a>
{% endfor %}

If a blog post draft is not discoverable, and it has any new tags used by no published blog posts, then those tag pages do not yet exist. Turn on ignore_missing to allow such drafts to be built. The tag-page URL path will be the empty string "", until the draft is published and the tag page is created.


Advanced configuration. An expression for the set of tags. The default expression is:

tags = parent.children.distinct("tags")

If you set tags_field to a different field name than "tags", the default expression uses your custom field name. For example if you have this line in tags.ini:

tags_field = labels

Then the default value of tags is:

tags = parent.children.distinct("labels")

You can use any template expression. For example, if your items have a "published" boolean field, you can select tags of published items:

tags = parent.children.filter(F.published).distinct("tags")

Or even list your tags manually:

tags = ["tag1", "tag2"]

See the Lektor documentation for queries.

Tags are always deduplicated, and alphabetically ordered.

Project details

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Files for lektor-tags, version 0.3
Filename, size File type Python version Upload date Hashes
Filename, size lektor_tags-0.3-py3-none-any.whl (5.7 kB) File type Wheel Python version py3 Upload date Hashes View
Filename, size lektor-tags-0.3.tar.gz (5.8 kB) File type Source Python version None Upload date Hashes View

Supported by

AWS AWS Cloud computing Datadog Datadog Monitoring DigiCert DigiCert EV certificate Facebook / Instagram Facebook / Instagram PSF Sponsor Fastly Fastly CDN Google Google Object Storage and Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Salesforce Salesforce PSF Sponsor Sentry Sentry Error logging StatusPage StatusPage Status page