My Book!


Unique Tag Cloud for Each Category in Pelican

Share this article: TwitterFacebookGoogle+Diaspora*Email

Pelican allows you to put articles into different 'categories'. On this site, I have the Blog and Projects categories. I wanted 'Projects' to be able to function as a portfolio. Ideally, it would have a tag cloud to allow someone to see all the different tools I've used for different projects, and easily find projects that involved the tools they're interested in.

By default, Pelican does not have a tag cloud. In recent versions, they've taken the tag cloud functionality out of the main program and put it into a plugin. However, the plugin counts all tags across all articles, meaning my 'Blog' tags would be mixed in with the 'Projects' tags. I ended up needing to modify the plugin to get the functionality I wanted. Instructions in case you want to do the same thing are below.

Set up

Since I modified the base tag_cloud plugin, the set up is very similar to that described on the official tag cloud plugin page. First, pelicanconf.py needs to be modified to look for the tag cloud plugin. If this is your first plugin, you should simply add these lines:

PLUGIN_PATHS = ["plugins"]
PLUGINS = ["tag_cloud"]

Otherwise, just add "tag_cloud" to your current PLUGINS list.

Next, you'll need the tag_cloud.py file, and need to place it in your plugins folder. You can download my version of tag_cloud.py from the github repo.

The basic change from the original script is that instead of having a tag_cloud structure with just a list of the tags, tag_cloud is a dictionary with each key being a category and each value being a tag list. The hard part is that Pelican doesn't allow you to use dictionaries in its templates - it converts everything to a list. For clarity, I change the dictionary to a list before passing it to the generator. In the templates I use Jinga2 to loop through all of the entries and find the matching category, like an inefficient dictionary, as explained below.

Displaying the tag cloud

To display the tag clouds is a little more complicated than with the basic plugin. You probably don't want to tag clouds showing up on every page - I only wanted them on the category pages themselves, article pages, and tags pages.

The different themes all have similar structures, but some might be a bit different. I use the blueidea theme.

To have the tag list for a category appear on article pages, the following code should be added article.html:

<div id="tagcloud">
    {% for cat in tag_cloud %}
        {% if article.category == cat.0 %}
                <b><center>{{ cat.0 }} Tags</center></b>
                <ul class="tagcloud">
                    {% for tag in cat.1 %}
                        <li class="tag-{{ tag.1 }}">
                            <a href="{{ SITEURL }}/{{ tag.0.url }}">
                                {{ tag.0 }}
                                {% if TAG_CLOUD_BADGE %}
                                    <span class="badge">({{ tag.2 }})</span>
                                {% endif %}
                            </a>
                        </li>
                    {% endfor %}                        
            </ul> 
         {% endif %}
     {% endfor %}
</div>

The placement of the code depends a bit on how you plan to style it and where you want it to show up. I have mine near the top, right below {% block content %}

To add the tag cloud to the tags and categories pages, the same code needs to be added to index.html. Place it within the first item conditional, right after this:

{# First item #}
{% if loop.first and not articles_page.has_previous() %}

This will take the category of the first article appearing on the page and generate the appropriate category tag cloud.

Settings and CSS Styling

The tag cloud should now display, just not necessarily how you want or where you want.

The plugin allows you to have different sizes for tags based on how common they are. This can be altered by changing the TAG_CLOUD_STEPS value (default is 4, you can set TAG_CLOUD_STEPS=num in pelicanconf.py). So use the following, adding as many li.tag-# as you have TAG_CLOUD_STEPS. You can also style the tag cloud list any way you want:

ul.tagcloud {
  list-style: none;
    padding: 0;
}

ul.tagcloud li {
    display: inline-block;
}

li.tag-1 {
    font-size: 150%;
}

li.tag-2 {
    font-size: 120%;
}

You can also use CSS to style the div the tag appears in. Here is mine:

div#tagcloud{   
    right: -150px;
    top: 250px;
    position: absolute;
    width: 140px;
    background: white;
    border-radius: 10px 10px 10px 10px;
    -moz-border-radius: 10px 10px 10px 10px;
    -webkit-border-radius: 10px 10px 10px 10px;
}

(I have a fixed-width wrapper around everything including my tagcloud, so this positioning puts my sidebar just outside of the main content area)

Full list of settings and defaults (you can add these lines to pelicanconf.py and change whatever values you want. If they don't exist in pelicanconf.py the defaults will be used):

TAG_CLOUD_STEPS=4 #number of different sizes of fonts in the tag cloud
TAG_CLOUD_MAX_ITEMS=100 #number of different tags that can appear in tag cloud
TAG_CLOUD_SORTING='size' #how tags will be ordered in the tag cloud. Valid values: random, alphabetically, alphabetically-rev, size and size-rev
TAG_CLOUD_BADGE=True #If True, displays the number of articles in each tag

Known issues

If you have overlap in the tags used between the two categories, the page for that tag will give the tag cloud for whatever the first article on the page is for that tag.

Since I used the same names as for the basic tag cloud plugin, this is not compatible with the base tag cloud.

If this somehow becomes popular, I might try to make this plugin a bit more official - giving it a unique name, adding some tests, and creating a tagcloud.html file that just gets included instead of copying and pasting the same code to two separate locations. So if you're using the plugin (or interested in it), let me know! Right now I only put in enough work to get it working for myself.





Comments !

social