A Python macro in bDS is a small script that automatically generates its own HTML content when rendering a post. In this post, we will build a macro together that creates a colored tag cloud β€” step by step, from the first "Hello World" to the finished visualization.

What we build

A tag cloud that displays all the tags of the blog. Each tag is labeled with the number of its posts. The color is determined by the frequency: rarely used tags appear in blue, frequently used ones in red β€” in between are green and yellow.

Step 1: Create a new script

In the sidebar of bDS, you will find the Scripts section. Click on New Script there.

In the editor, you will now see several fields:

  • Title β€” Give your script a name, e.g. Awesome-Tag-Cloud
  • Slug β€” Automatically generated, e.g. awesome_tag_cloud. Under this name, you will later call the macro in the post
  • Type β€” Select macro here
  • Entry point β€” Select main (automatically recognized as soon as you have a function main in the code)
  • Activated β€” Check the box so that the macro is also executed during rendering

Step 2: A minimal macro

Enter the following code in the Script content area:

async def main(context, post_data):
    return {
        'html': '<p>Hello from the macro!</p>'
    }

Click on Save Script. You can test with Check Syntax whether the code is error-free.

To use the macro in a post, simply write at the desired location:

[[awesome_tag_cloud]]

When rendering, this placeholder is replaced by the HTML text β€” in this case simply "Hello from the macro!".

Step 3: Determine tags and post numbers

Now we expand the script. Via the built-in interface bds_api, the macro can access all the data of the blog. We load all tags and all posts and count how often each tag is used:

from bds_api import bds

async def main(context, post_data):
    # Load all tags
    tags = await bds.tags.get_all()

    # Load all posts
    result = await bds.posts.get_all()
    posts = result['items']

    # Count how often each tag occurs
    counter = {}
    for post in posts:
        for tag in post.get('tags', []):
            counter[tag] = counter.get(tag, 0) + 1

    # Output as text for control
    lines = []
    for tag in tags:
        name = tag['name']
        count = counter.get(name, 0)
        lines.append(f'{name}: {count} post/posts')

    return {
        'html': '<br>'.join(lines)
    }

After saving, the macro displays a simple list when rendering: each tag with the number of its posts.

Step 4: The tag cloud as a colored representation

In the last step, we convert the output into a real tag cloud. The tags are displayed in different sizes and colors β€” depending on the frequency. The color scale ranges from blue (few posts) via green and yellow to red (many posts).

from bds_api import bds

async def main(context, post_data):
    tags = await bds.tags.get_all()
    result = await bds.posts.get_all()
    posts = result['items']

    counter = {}
    for post in posts:
        for tag in post.get('tags', []):
            counter[tag] = counter.get(tag, 0) + 1

    # Determine the range of frequencies
    values = [counter.get(t['name'], 0) for t in tags]
    if not values or max(values) == 0:
        return {'html': '<p>No tags with posts found.</p>'}

    min_val = min(values)
    max_val = max(values)
    span = max_val - min_val if max_val != min_val else 1

    # Calculate color on the scale blue β†’ green β†’ yellow β†’ red
    def color_for(share):
        if share < 0.33:
            # Blue β†’ Green
            t = share / 0.33
            r = 0
            g = int(128 + 127 * t)
            b = int(200 * (1 - t))
        elif share < 0.66:
            # Green β†’ Yellow
            t = (share - 0.33) / 0.33
            r = int(255 * t)
            g = 220
            b = 0
        else:
            # Yellow β†’ Red
            t = (share - 0.66) / 0.34
            r = 220
            g = int(200 * (1 - t))
            b = 0
        return f'rgb({r},{g},{b})'

    # Build HTML
    elements = []
    for tag in tags:
        name = tag['name']
        count = counter.get(name, 0)
        share = (count - min_val) / span
        size = 0.8 + share * 1.6  # 0.8em to 2.4em
        color = color_for(share)
        elements.append(
            f'<span style="font-size:{size:.1f}em;color:{color};'
            f'padding:4px 8px;display:inline-block;cursor:default" '
            f'title="{count} post(s)">'
            f'{name} <sup style="font-size:0.6em">({count})</sup></span>'
        )

    html = (
        '<div style="line-height:2.2;text-align:center;'
        'padding:16px;border:1px solid #e0e0e0;border-radius:8px">'
        + ' '.join(elements)
        + '</div>'
    )

    return {'html': html}

How the coloring works

The color is calculated based on the share β€” i.e., how the frequency of a tag compares to all others:

ShareColor
0 % – 33 %Blue β†’ Green
33 % – 66 %Green β†’ Yellow
66 % – 100 %Yellow β†’ Red

Tags with few posts are therefore rather cool (blue), frequently used tags rather warm (red). In addition, the font size is adjusted: rare tags appear smaller, frequent ones larger.

Summary

StepWhat happens
Create a new scriptVia Scripts β†’ New Script in the sidebar
Select typeSet Type to macro
Write codeIn the Script content area
ActivateCheck Activated
Use in postWrite [[awesome_tag_cloud]] at the desired location

The macro is executed again with every preview and every publication β€” the tag cloud is therefore always up to date.