Aggregate Blogs with Pelican

I use Pelican for my website, including this blog, and I love it. So when the time came to start working on our professional website, it was the obvious choice.

One thing we wanted was a page that aggregates our blogs. A view on what the individual members of the collective do.

We thought about deploying a planet like Venus, but that would have implied essentially doing the theming work twice: once for the website, and once for the planet.

The rest of our website is made with Pelican, so we figured it would be nicer to use something that integrates with that. And so I just wrote a small Pelican plugin which does just that: pelican-planet.

It's quite simple to use, just install it:

$ pip install pelican-planet

Then, in your pelicanconf.py file, enable the plugin and declare the feeds you want to aggregate:

PLUGINS = [
    ...
    'pelican_planet',
    ...
    ]

PLANET_FEEDS = {
    'Some amazing blog': 'https://example1.org/feeds/blog.atom.xml',
    'Another great blog': 'https://example2.org/feeds/blog.atom.xml',
    ...
    }

Now you need to write a Jinja2 template for the planet page. A simple one to generate a Markdown page could be:

title: The Fantastic Planet
slug: planet

Some blogs aggregated here.

{% for article in articles %}
# {{ article.title }}

{% endfor %}

Finally, declare your template as well as the path to the generated page:

PLANET_TEMPLATE = 'content/planet.md.tmpl'
PLANET_PAGE = 'content/planet.md'

Now, when you rebuild your website, the pelican-planet plugin will download the feeds, and generate the page out of the template, then Pelican will build the website, including that page, as if it was one you had written normally.

You'll probably want to setup a systemd timer or a cron job to rebuild your website regularly, so that the planet page gets refreshed with new articles from the aggregated feeds.

Each article object will have a title, an author, a link to the original post, a summary, and a couple of other attributes.

Of course the planet template can be much more complex than the above trivial example. For example, we're not using Markdown but directly HTML as that allows us to really do anything we could possibly want with the result. Here's the relevant part of our template:

{% for article in articles %}
  <div class="article">
    <h2><a href="{{ article.link }}">{{ article.title }}</a></h2>
    <p class="article-metadata">{{ article.author }}&nbsp;{{ article.updated.strftime("%Y-%m-%d") }}</p>
    <div class="article-summary">
      {{ article.summary }}
    </div>
  </div>
  {% if not loop.last %}
    <hr>
  {% endif %}
{% endfor %}

Hopefully this can be useful to somebody else, but if not we're already happily using it over at Kymeria.fr.

Do let us know if you deploy it, report issues or feature requests, and send merge requests to make it better suited to your use case.