Plugins

In this tutorial we’re going to build a Tag Cloud content object. It will provide a way to inject counts of how many times tags appear on selected objects.

We start by creating a plugins.py in our project, and declaring TagCloud as a sub-class of gilbert.content.Content:

plugins.py
1from gilbert.content import Content
2
3
4class TagCloud(Content):
5    pass

Next, we need to gather all the content objects and aggregate the tags.

plugins.py
 1from collections import Counter
 2
 3from gilbert.content import Content
 4
 5
 6class TagCloud(Content):
 7
 8    @property
 9    def tag_counts(self):
10        tags = Counter()
11        for obj in self.site.content:
12            tags.update(obj.tags)
13        return tags

And that’s it! We can create a content object with content_type: TagCloud, and access it in our templates by looking it up in site.content[], and accessing its tag_counts property.

Oh, but wait - maybe we don’t want to count all the objects? Let’s add a filter.

plugins.py
 1from collections import Counter
 2
 3from gilbert.content import Content
 4
 5class TagCloud(Content):
 6    filter_by : dict = {}
 7
 8    @property
 9    def tag_counts(self):
10        tags = Counter()
11        for obj in self.site.content.matches(self.filter_by):
12            tags.update(obj.tags)
13        return tags

Now our users can declare a filter using Object Queries to limit which objects will be scanned.

This is nice, but as our site grows, collecting these each time we render will start to get expensive.

plugins.py
 1from collections import Counter
 2from functools import cached_property
 3
 4from gilbert.content import Content
 5
 6class TagCloud(Content):
 7    filter_by : dict = {}
 8
 9    @cached_property
10    def tag_counts(self):
11        tags = Counter()
12        for obj in self.site.pages.matching(self.filter_by):
13            tags.update(obj.tags)
14         return tags

So here we use Python’s cached_property decorator, which works like property but caches the result so it only invokes the function once, saving the result on the instance; future accesses are super fast as they’re handled internally within Python.