A flying Pelican

Introduction to Pelican

There are lots of static site generators (SSG) available in the market. When it comes to Python based SSG, Pelican is the most popular one.

Here is my thoughts on Pelican:

  • Pelican is written in Python and is easy to use.
  • Pelican uses Jinja2 as the template language or macro. Which is not bad because Ansible templates is also using Jinja2. Learning Jinja2 is beneficial beneficial on using both products.
  • If you are a data scientist, you could integrate Pelican with Jupyter Notebooks. When it comes to data science, Python is the big player and really shines.
  • IMO, the development of Pelican is not very active compared with other popular SSG like Gatsby or Hugo. Pelican is not under the spotlight.
  • SEO could be a weakness or problem for Pelican. Not all Pelican themes are SEO optimized. Also, there are no or few working plugins for SEO.
  • Pelican is not a PWA (Progressive Web App). If you need a PWA, you need to look for other products.

Install Pelican

Software requirement:

  • Python
  • Suggested to use a Python virtual environment to install Pelican
  • Suggested to install a local web server with SSL to serve the output from Pelican instead of serving it on a non-standard port. This is to avoid having problem when testing links (Content Security Policy) with HTTPS in development and production environment
1
2
3
4
5
6
7
8
cd ~
python -m venv pelican
source ~/pelican/bin/activate
pip install pelican

mkdir blog-data
cd blog-data
pelican-quickstart

The pelican-quickstart command generates a set of files for you to use Pelican.

  • For the questions and answers, accepting the default setting or change it to suit your local setting.
  • For time zone setting, refer to the official site and Wikipedia.
  • If you had created a local web server, put your local domain name in SITEURL of pelicanconf.py. This is for local browsing your blog. For example, SITEURL = 'https://myblog.test' All html generated would use this domain name.
  • If you do have a local web server for serving the output from Pelican. You would need to rely on the internal web server provided by Pelican. Refer to the official site for details.
  • Update the SITEURL parameter of publishconf.py by your internet domain name. This is used when the template generates your content for publishing to the internet.

Configure the structure of your website

Pelican is a SSG, so there would be articles (or blogs), pages (seldom changes, like an 'About me' or 'Contact' page). In Pelican, an article would be categorized as a single category. There is a plugin that enable support of multiple categories. An article would have one or more tags. In Pelican, it could be configured to generate archive per month and per year.

The structure of a typical article would be like this:

Article

  • Title: My first post
  • Category: siteinfo
  • Slug: first-post
  • URL: /posts/siteinfo/2020/06/24/first-post

Related setting in pelicanconf.py:

You don't have to use 'posts', you can use 'article' or 'blog'.

For this website you are reading, I would like to have articles inside a category separated by year, month and date. I don't want lots of articles with different creation dates mixed together a in directory. But some SEO tools said my URLs are too long. The structure of the URL is your call.

So, for my setup, it would be these parameters for pelicanconf.py.

1
2
3
4
5
ARTICLE_URL = 'posts/{category}/{date:%Y}/{date:%m}/{date:%d}/{slug}/'
ARTICLE_SAVE_AS = 'posts/{category}/{date:%Y}/{date:%m}/{date:%d}/{slug}/index.html'

PAGE_URL = 'pages/{slug}/'
PAGE_SAVE_AS = 'pages/{slug}/index.html'

{slug} is the name generated from the metadata of your raw text file in restructuredText or Markdown format. We will look at the metadata of a raw source file.

Creating an article

By default, the content/ directory stores your raw source file for articles and pages. So, we are going to create an article called 'My first post'.

1
2
3
4
cd ~/blog-data/content
mkdir -p posts/siteinfo
cd posts/siteinfo
vi first-post.rst

Content of first-post.rst (restructuredText)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
My first post
#############

:date: 2020-06-24
:modified: 2020-06-24
:author: John Doe
:category: siteinfo
:tags: blog
:slug: first-post
:status: published
:summary: This is the first post of this website

Welcome to my blog. This is my first post.

If you are using Markdown, create a file first-post.md in Markdown format

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
Title: My first post
Date: 2020-06-24
Modified: 2020-06-24
Authors: John Doe
Category: siteinfo
Tags: blog
Slug: first-post
Status: published
Summary: This is the first post of this website

Welcome to my blog. This is my first post.

Generate articles and Previewing

To preview the article, we need to generate it.

1
2
cd ~/blog-data
make html

The static page would be generated the OUTPUTDIR specified in the Makefile, which is ~/blog-data/output. Refer to official documentation if necessary.

Pelican would generate the output filename from slug, in this example

  • The URL of this article is /posts/siteinfo/2020/06/24/first-post/
  • The output file is /posts/siteinfo/2020/06/24/first-post/index.html

These are related to ARTICLE_URL and ARTICLE_SAVE_AS we had mentioned before. When we use the 'make html' command, the parameters from pelicanconf.py is used.

If you are previewing the generated content locally, you can copy the files from blog-data/output to the document root of the local web server. You may also setup a symbolic link from the document root of the web server to the blog-data/output with read permission.

Publishing

After you have finished editing the articles, you could publish it.

1
2
cd ~/blog-data
make publish

When we use the 'make publish' command, the parameters from pelicanconf.py is used first. Then any parameters specified in publishconf.py would override the settings in pelicanconf.py. Remember we had set our public internet domain in SITEURL in publishconf.py? All the links in generated html would use the public internet domain. The output files are located inside ~/blog-data/output. Then you could upload the content to your web hosting service provider.

Different hosting service provides would have different workflow for uploading your web content. For advanced usage you may want to have a pipeline utilizing GitHub with CI/CD, automating the publish of your web content.

Choosing a theme

For users not familiar with Pelican or do not want to write a new theme, I would suggest they use an existing theme. Themes varies a lot. Some are not optimized with SEO. But you can customize it by yourself if you want.

pelican-themes provides a list of themes. Personally, I did not try all of them. To save time, here are some of the themes to note for new users of Pelican:

  • Elegant - As the name suggested, it is an elegant theme with unique features. Check out the author site for how it looks

  • m.css - Using Pure CSS, no JavaScript is needed by this theme. Also, check the plugins. The plugins are uniques. The HTML sanity plugin generates valid HTML 5 markup. It uses the docutils HTML5 writer, instead of using the HTML4/CSS1 writer or fixing with BeautifulSoap on top of the generated HTML

  • Attila - The Pelican version of the Ghost theme

  • VoidyBootstrap - Based on Bootstrap 3

  • pelican-bootstrap3

    This is a very basic starting theme if you want to customize. Quite a lot of features were written. But areas like SEO need improvement. Also note the Boostrap 3 framework is getting older and there would be no update.

My current theme

My current theme is pelican-kappa-nero

This is the theme I am using. I customize it from pelican-bootstrap3. I created it because I wanted a dark theme. Below is the history of the theme, you may skip it in go directly to the next section.

There are two more side projects before it becomes my current theme. pelican-bootstrap3-nero is my first theme that is forked from pelican-bootstrap3. Most settings and options of the theme are still retained.

pelican-bootstrap4-nero is my second theme. It is based on pelican-bootstrap3-nero. It uses the Bootstrap 4 framework. But I did not migrate all the codes from BS3 to BS4. Nor I want it to be the official pelican-bootstrap4. You are free to fork the theme and customize it.

Finally, it's my current theme, pelican-kappa-nero. It is based on pelican-bootstrap4-nero. Starting with this theme, I would make customization to my needs and preference. More codes in pelican-bootstrap3 could break or not working. Local customizations were made, like SEO, JSON-LD, integration with Meilisearch and etc.

Please note both pelican-bootstrap3-nero and pelican-bootstrap4-nero are not maintained anymore. All the development work is focused on my current theme.

Setup my current theme

For the theme that I am currently using, the setup would be like below. The first 'git clone' is for the theme. The second 'git clone' is for the plugins for Pelican.

1
2
3
cd ~
git clone https://github.com/kappa-wingman/pelican-kappa-nero.git
git clone https://github.com/getpelican/pelican-plugins.git

In your pelicanconf.py, specify these parameters:

1
2
3
4
THEME = '../pelican-kappa-nero'
JINJA_ENVIRONMENT = {'extensions': ['jinja2.ext.i18n']}
PLUGIN_PATHS = ['../pelican-plugins']
PLUGINS = ['i18n_subsites']

i18n is needed because of the used of JINJA extension.

Then you can regenerate your static web pages by 'make html' or 'make publish'.

Conclusion and further reading

So, now you could publish articles with Pelican. This is the first step. There are areas that you could work on:

  • Improving the theme
    • SEO, adding features, updating UI and etc.
  • Developing your own theme

Further reading

Photo credit: Alfred Leung (Unsplash license)


Share this post on: TwitterRedditEmailHackerNewsLinkedInFacebookIndienews