The Digital Cat - pelicanhttps://www.thedigitalcatonline.com/2021-03-25T14:00:00+01:00Adventures of a curious cat in the land of programmingHow to write a Pelican theme for your static website2021-03-25T14:00:00+01:002021-03-25T14:00:00+01:00Leonardo Giordanitag:www.thedigitalcatonline.com,2021-03-25:/blog/2021/03/25/how-to-write-a-pelican-theme-for-your-static-website/<p>A full-fledged tutorial that shows how to convert an HTML template into a Pelican theme</p><p>I run The Digital Cat using a static site generator called <a href="https://blog.getpelican.com/">Pelican</a>, created by my friend <a href="https://justinmayer.com/">Justin Mayer</a> and actively maintained by him and other developers. I also gave some minor contributions to the project.</p><p>Since I started working on the blog in 2013 I run a great length to customise the theme that I use. I initially went for a pre-made Pelican theme, but I soon started to change small things, and eventually ended up creating a whole new theme that suits my needs.</p><p>Front-end development if not my forte, though, so I didn't want to start from scratch with HTML, CSS and JS. My knowledge of those tools is limited, and I have other interests, so I started from a free (CC BY 3.0) pre-made HTML5 template created by <a href="https://html5up.net/">HTML5 UP</a>. You can see <a href="https://html5up.net/editorial">a demo of the original template</a> and compare it with what you see on this very page.</p><p>Encouraged by Justin, I decided to write down this initial guide on how to port a Pelican theme from a static template. I will show you how to start a blog from scratch, how to get a static template and how to make it usable by Pelican. Everything done step by step without skipping any passage. At the end of the post you will <strong>have a running blog with some demo articles</strong>, you will <strong>have learned how to use the Jinja language and the Pelican variables</strong>, and you will <strong>have an idea of what to do next to further customise your static website</strong>.</p><p>Let's start!</p><h2 id="initial-setup-7d57">Initial setup<a class="headerlink" href="#initial-setup-7d57" title="Permanent link">¶</a></h2><p>Let's create a blog called The Analog Fox, following <a href="https://docs.getpelican.com/en/latest/quickstart.html">Pelican's quickstart guide</a>.</p><p>I created a virtual environment and installed Pelican as suggested, then run</p><div class="code"><div class="content"><div class="highlight"><pre>mkdir theanalogfox
cd theanalogfox
pelican-quickstart
</pre></div> </div> </div><p>For this project I will only run the blog locally, so I didn't configure any specific way to publish it, neither properly set up a URL prefix. If you are about to create a real website please read Pelican's documentation about those settings.</p><div class="code"><div class="content"><div class="highlight"><pre>> Where do you want to create your new web site? [.]
<span class="hll">> What will be the title of this web site? The Analog Fox
</span><span class="hll">> Who will be the author of this web site? Leonardo Giordani
</span>> What will be the default language of this web site? [en]
<span class="hll">> Do you want to specify a URL prefix? e.g., https://example.com (Y/n) n
</span>> Do you want to enable article pagination? (Y/n)
<span class="hll">> How many articles per page do you want? [10] 3
</span>> What is your time zone? [Europe/Paris]
> Do you want to generate a tasks.py/Makefile to automate generation and publishing? (Y/n)
> Do you want to upload your website using FTP? (y/N)
> Do you want to upload your website using SSH? (y/N)
> Do you want to upload your website using Dropbox? (y/N)
> Do you want to upload your website using S3? (y/N)
> Do you want to upload your website using Rackspace Cloud Files? (y/N)
> Do you want to upload your website using GitHub Pages? (y/N)
Done. Your new project is available at /home/leo/devel/theanalogfox
</pre></div> </div> </div><p>If you run <code>pelican -lr</code> now and visit <a href="http://localhost:8000">http://localhost:8000</a> with your browser you will see the first page of the blog rendered with the default theme.</p><h2 id="demo-content-a90a">Demo content<a class="headerlink" href="#demo-content-a90a" title="Permanent link">¶</a></h2><p>Before we venture into the jungle of Jinja templates it's worth creating some content. As this is a very boring activity I prepared a little script that you can run in the terminal.</p><div class="code"><div class="content"><div class="highlight"><pre><span class="ch">#!/bin/bash</span>
<span class="nv">NUM_POSTS</span><span class="o">=</span><span class="m">20</span>
<span class="nv">CONTENT_DIR</span><span class="o">=</span>content
<span class="nv">LOREM_API</span><span class="o">=</span>https://jaspervdj.be/lorem-markdownum/markdown.txt
<span class="nv">IMAGES_API</span><span class="o">=</span>https://placeimg.com/1000/341/animals
rm<span class="w"> </span>-fR<span class="w"> </span>content
mkdir<span class="w"> </span>-p<span class="w"> </span>content/images
<span class="k">for</span><span class="w"> </span>i<span class="w"> </span><span class="k">in</span><span class="w"> </span><span class="k">$(</span>seq<span class="w"> </span>-w<span class="w"> </span><span class="m">1</span><span class="w"> </span><span class="si">${</span><span class="nv">NUM_POSTS</span><span class="si">}</span><span class="k">)</span>
<span class="k">do</span>
<span class="w"> </span><span class="nv">post_file</span><span class="o">=</span><span class="si">${</span><span class="nv">CONTENT_DIR</span><span class="si">}</span>/post<span class="si">${</span><span class="nv">i</span><span class="si">}</span>.markdown
<span class="w"> </span><span class="nb">echo</span><span class="w"> </span><span class="s2">"Creating post </span><span class="si">${</span><span class="nv">i</span><span class="si">}</span><span class="s2">"</span>
<span class="w"> </span><span class="nb">echo</span><span class="w"> </span><span class="s2">"Title: A sample article </span><span class="si">${</span><span class="nv">i</span><span class="si">}</span><span class="s2">"</span><span class="w"> </span>>><span class="w"> </span><span class="si">${</span><span class="nv">post_file</span><span class="si">}</span>
<span class="w"> </span><span class="nb">echo</span><span class="w"> </span><span class="s2">"Date: 2021-03-</span><span class="si">${</span><span class="nv">i</span><span class="si">}</span><span class="s2">"</span><span class="w"> </span>>><span class="w"> </span><span class="si">${</span><span class="nv">post_file</span><span class="si">}</span>
<span class="w"> </span><span class="nb">echo</span><span class="w"> </span><span class="s2">"Category: News"</span><span class="w"> </span>>><span class="w"> </span><span class="si">${</span><span class="nv">post_file</span><span class="si">}</span>
<span class="w"> </span><span class="nb">echo</span><span class="w"> </span><span class="s2">"Tags: </span><span class="k">$(</span>seq<span class="w"> </span><span class="m">1</span><span class="w"> </span><span class="m">20</span><span class="w"> </span><span class="p">|</span><span class="w"> </span>shuf<span class="w"> </span><span class="p">|</span><span class="w"> </span>head<span class="w"> </span>-n3<span class="w"> </span><span class="p">|</span><span class="w"> </span>sed<span class="w"> </span>-r<span class="w"> </span>s,<span class="s2">"^"</span>,<span class="s2">"tag"</span>,<span class="w"> </span><span class="p">|</span><span class="w"> </span>paste<span class="w"> </span>-sd<span class="w"> </span><span class="s2">","</span><span class="w"> </span>-<span class="k">)</span><span class="s2">"</span><span class="w"> </span>>><span class="w"> </span><span class="si">${</span><span class="nv">post_file</span><span class="si">}</span>
<span class="w"> </span><span class="nb">echo</span><span class="w"> </span><span class="s2">"Image: post</span><span class="si">${</span><span class="nv">i</span><span class="si">}</span><span class="s2">.jpg"</span><span class="w"> </span>>><span class="w"> </span><span class="si">${</span><span class="nv">post_file</span><span class="si">}</span>
<span class="w"> </span><span class="nb">echo</span><span class="w"> </span><span class="s2">"Summary: Summary of post </span><span class="si">${</span><span class="nv">i</span><span class="si">}</span><span class="s2">"</span><span class="w"> </span>>><span class="w"> </span><span class="si">${</span><span class="nv">post_file</span><span class="si">}</span>
<span class="w"> </span><span class="nb">echo</span><span class="w"> </span>>><span class="w"> </span><span class="si">${</span><span class="nv">post_file</span><span class="si">}</span>
<span class="w"> </span>curl<span class="w"> </span>-s<span class="w"> </span><span class="si">${</span><span class="nv">LOREM_API</span><span class="si">}</span><span class="w"> </span><span class="p">|</span><span class="w"> </span>sed<span class="w"> </span>-r<span class="w"> </span>s,<span class="s2">"^#"</span>,<span class="s2">"##"</span>,<span class="w"> </span>>><span class="w"> </span><span class="si">${</span><span class="nv">post_file</span><span class="si">}</span>
<span class="w"> </span>curl<span class="w"> </span>-s<span class="w"> </span><span class="si">${</span><span class="nv">IMAGES_API</span><span class="si">}</span><span class="w"> </span>><span class="w"> </span><span class="si">${</span><span class="nv">CONTENT_DIR</span><span class="si">}</span>/images/post<span class="si">${</span><span class="nv">i</span><span class="si">}</span>.jpg
<span class="k">done</span>
</pre></div> </div> </div><p>Save it as <code>create_content.sh</code> and give it execution permissions with <code>chmod 775 create_content.sh</code>. At this point you can run it with <code>./create_content.sh</code> and it will create the directory <code>content</code> with 20 posts and an image for each of them. You can safely run it multiple times, it will automatically delete the previous output.</p><p>If you know bash feel free to hack the script to do something more complicated, but this very simple program does everything we need to work on Pelican themes.</p><p>Running <code>pelican -lr</code> and visiting <a href="http://localhost:8000">http://localhost:8000</a> will now show a richer website.</p>
<div class="advertisement">
<a href="https://www.thedigitalcat.academy/freebie-first-class-objects">
<img src="/images/first-class-objects/cover.jpg" />
</a>
<div class="body">
<h2 id="first-class-objects-in-python-fffa">First-class objects in Python<a class="headerlink" href="#first-class-objects-in-python-fffa" title="Permanent link">¶</a></h2>
<p>Higher-order functions, wrappers, and factories</p>
<p>Learn all you need to know to understand first-class citizenship in Python, the gateway to grasp how decorators work and how functional programming can supercharge your code.</p>
<div class="actions">
<a class="action" href="https://www.thedigitalcat.academy/freebie-first-class-objects">Get your FREE copy</a>
</div>
</div>
</div>
<h2 id="the-template-f1ec">The template<a class="headerlink" href="#the-template-f1ec" title="Permanent link">¶</a></h2><p>From now on I will make extensive use of the documentation at <a href="https://docs.getpelican.com/en/latest/themes.html#creating-themes">https://docs.getpelican.com/en/latest/themes.html#creating-themes</a>, so please be sure to have that page open in your browser.</p><p>For this tutorial I will use the template "Future Imperfect" by <a href="https://html5up.net/">HTML5 UP</a>. The template can be seen in action <a href="https://html5up.net/future-imperfect">at this page</a>, and you can download it using the button in the top right corner of the page itself.</p><p>Please consider supporting HTML UP even only with a Tweet. Being a content creator myself I know how important it can be to receive any type of feedback from readers/users.</p><p>Let's have a quick look at the template before we dive into the core of the post. We have a navbar at the top of the screen, with a link to the homepage, several links to specific pages, a search button, and a menu. In the body of the page there is a sidebar on the left and a preview of the articles on the right.</p><p>The sidebar contains the title and the subtitle of the blog, two lists of posts, the about section, and some social buttons. The first list of posts features image, title, date, and the avatar of the author, while the second list has just a small thumbnail, title, and date. Each post in the main list shows the full image, title, subtitle, name and avatar of the author, publication date, a preview of the content of the article, and a button that links the full version of the article. Last, tags are listed at the bottom right, just next to the number of likes and comments.</p><p>Just to be clear from the start, I won't implement everything we see here in my Pelican theme. I won't touch the navbar, and I won't discuss likes and comments, which require external systems when it comes to static sites. I will also simplify the sidebar, using only one list of posts. Moreover, I will not preview the articles in the main page, but print the full content.</p><p>Unzip the template archive in a subdirectory of the blog directory called <code>future-imperfect</code>. The archive doesn't contains a root folder, so you need to create it explicitly.</p><p>Enter the theme directory and change the layout of the files to follow <a href="https://docs.getpelican.com/en/latest/themes.html#structure">Pelican's requirements</a>:</p><div class="code"><div class="content"><div class="highlight"><pre>mv assets/ static
mv images/ static/
mkdir templates
mv *.html templates/
</pre></div> </div> </div><p>At this point edit the file <code>pelicanconf.py</code> in the main directory of the blog, adding the variable <code>THEME</code></p><div class="code"><div class="title"><code>pelicanconf.py</code></div><div class="content"><div class="highlight"><pre><span class="n">PATH</span> <span class="o">=</span> <span class="s1">'content'</span>
<span class="hll"><span class="n">THEME</span> <span class="o">=</span> <span class="s2">"future-imperfect"</span>
</span>
<span class="n">TIMEZONE</span> <span class="o">=</span> <span class="s1">'Europe/Paris'</span>
<span class="n">DEFAULT_LANG</span> <span class="o">=</span> <span class="s1">'en'</span>
</pre></div> </div> </div><p>If you refresh the blog page now you will see that the output doesn't even have a working style sheet, but don't worry, Pelican is still working correctly. We are overriding Pelican's output with the file <code>future-imperfect/templates/index.html</code>, which is supposed to be a Jinja template, but being part of the HTML5 template is just injecting static content. In particular, the CSS/JS assets are not loaded correctly, as you can see.</p><p>Let's learn the first piece of syntax adjusting the CSS and JS links, then, so that we can at least have a good output to look at. We need to change the path <code>assets/</code> with <code>{{ SITEURL }}/theme/</code></p><div class="code"><div class="title"><code>future-imperfect/templates/index.html</code></div><div class="content"><div class="highlight"><pre><span class="cp"><!DOCTYPE HTML></span>
<span class="cm"><!--</span>
<span class="cm"> Future Imperfect by HTML5 UP</span>
<span class="cm"> html5up.net | @ajlkn</span>
<span class="cm"> Free for personal and commercial use under the CCA 3.0 license (html5up.net/license)</span>
<span class="cm"> --></span>
<span class="p"><</span><span class="nt">html</span><span class="p">></span>
<span class="p"><</span><span class="nt">head</span><span class="p">></span>
<span class="p"><</span><span class="nt">title</span><span class="p">></span>Future Imperfect by HTML5 UP<span class="p"></</span><span class="nt">title</span><span class="p">></span>
<span class="p"><</span><span class="nt">meta</span> <span class="na">charset</span><span class="o">=</span><span class="s">"utf-8"</span> <span class="p">/></span>
<span class="p"><</span><span class="nt">meta</span> <span class="na">name</span><span class="o">=</span><span class="s">"viewport"</span> <span class="na">content</span><span class="o">=</span><span class="s">"width=device-width, initial-scale=1, user-scalable=no"</span> <span class="p">/></span>
<span class="hll"> <span class="p"><</span><span class="nt">link</span> <span class="na">rel</span><span class="o">=</span><span class="s">"stylesheet"</span> <span class="na">href</span><span class="o">=</span><span class="s">"</span><span class="cp">{{</span> <span class="nv">SITEURL</span> <span class="cp">}}</span><span class="s">/theme/css/main.css"</span> <span class="p">/></span>
</span> <span class="p"></</span><span class="nt">head</span><span class="p">></span>
[...]
<span class="hll"> <span class="p"><</span><span class="nt">script</span> <span class="na">src</span><span class="o">=</span><span class="s">"</span><span class="cp">{{</span> <span class="nv">SITEURL</span> <span class="cp">}}</span><span class="s">/theme/js/jquery.min.js"</span><span class="p">></</span><span class="nt">script</span><span class="p">></span>
</span><span class="hll"> <span class="p"><</span><span class="nt">script</span> <span class="na">src</span><span class="o">=</span><span class="s">"</span><span class="cp">{{</span> <span class="nv">SITEURL</span> <span class="cp">}}</span><span class="s">/theme/js/browser.min.js"</span><span class="p">></</span><span class="nt">script</span><span class="p">></span>
</span><span class="hll"> <span class="p"><</span><span class="nt">script</span> <span class="na">src</span><span class="o">=</span><span class="s">"</span><span class="cp">{{</span> <span class="nv">SITEURL</span> <span class="cp">}}</span><span class="s">/theme/js/breakpoints.min.js"</span><span class="p">></</span><span class="nt">script</span><span class="p">></span>
</span><span class="hll"> <span class="p"><</span><span class="nt">script</span> <span class="na">src</span><span class="o">=</span><span class="s">"</span><span class="cp">{{</span> <span class="nv">SITEURL</span> <span class="cp">}}</span><span class="s">/theme/js/util.js"</span><span class="p">></</span><span class="nt">script</span><span class="p">></span>
</span><span class="hll"> <span class="p"><</span><span class="nt">script</span> <span class="na">src</span><span class="o">=</span><span class="s">"</span><span class="cp">{{</span> <span class="nv">SITEURL</span> <span class="cp">}}</span><span class="s">/theme/js/main.js"</span><span class="p">></</span><span class="nt">script</span><span class="p">></span>
</span>
<span class="p"></</span><span class="nt">body</span><span class="p">></span>
<span class="p"></</span><span class="nt">html</span><span class="p">></span>
</pre></div> </div> </div><p>We also need to correctly link images. Change any occurrence of <code>images/</code> into <code>{{ SITEURL}}/theme/images/</code>, e.g.</p><div class="code"><div class="content"><div class="highlight"><pre> <span class="p"><</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">"meta"</span><span class="p">></span>
<span class="p"><</span><span class="nt">time</span> <span class="na">class</span><span class="o">=</span><span class="s">"published"</span> <span class="na">datetime</span><span class="o">=</span><span class="s">"2015-11-01"</span><span class="p">></span>November 1, 2015<span class="p"></</span><span class="nt">time</span><span class="p">></span>
<span class="hll"> <span class="p"><</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">"#"</span> <span class="na">class</span><span class="o">=</span><span class="s">"author"</span><span class="p">><</span><span class="nt">span</span> <span class="na">class</span><span class="o">=</span><span class="s">"name"</span><span class="p">></span>Jane Doe<span class="p"></</span><span class="nt">span</span><span class="p">><</span><span class="nt">img</span> <span class="na">src</span><span class="o">=</span><span class="s">"</span><span class="cp">{{</span> <span class="nv">SITEURL</span> <span class="cp">}}</span><span class="s">/theme/images/avatar.jpg"</span> <span class="na">alt</span><span class="o">=</span><span class="s">""</span> <span class="p">/></</span><span class="nt">a</span><span class="p">></span>
</span> <span class="p"></</span><span class="nt">div</span><span class="p">></span>
<span class="p"></</span><span class="nt">header</span><span class="p">></span>
<span class="hll"> <span class="p"><</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">"single.html"</span> <span class="na">class</span><span class="o">=</span><span class="s">"image featured"</span><span class="p">><</span><span class="nt">img</span> <span class="na">src</span><span class="o">=</span><span class="s">"</span><span class="cp">{{</span> <span class="nv">SITEURL</span> <span class="cp">}}</span><span class="s">/theme/images/pic01.jpg"</span> <span class="na">alt</span><span class="o">=</span><span class="s">""</span> <span class="p">/></</span><span class="nt">a</span><span class="p">></span>
</pre></div> </div> </div><p>If you refresh the page after these changes you will see the template fully rendered (minus the images you saw in the demo, those are replaced by placeholders in the downloaded version).</p><p>A little trick: if you remove the comments at lines 177 and 487 you will get a nice recap of the graphical components of the template. I will not use them, so I removed lines 176-487, but remember that those cheat sheets can be very useful when trying to understand how a template works.</p><p>As I mentioned earlier, I also removed the third list of posts, as it doesn't add anything to what we will learn. You are clearly free to keep it and experiment with it.</p><h3 id="deep-dive-e364">Deep dive</h3><p>How does <code>{{ SITEURL }}/theme</code> work?</p><p>Pelican's <a href="https://docs.getpelican.com/en/latest/settings.html#themes">documentation on themes</a> says</p><div class="callout"><div class="content"><p><code>THEME_STATIC_DIR = 'theme'</code></p>
<p>Destination directory in the output path where Pelican will place the files collected from THEME<em>STATIC</em>PATHS. Default is theme.</p></div></div><p>the variable <code>THEME_STATIC_PATHS</code> is by default <code>static</code>, which is why we created that directory inside the theme.</p><p>As you can see all these paths are configurable, should you prefer different names.</p><h2 id="pelican-variables-db40">Pelican variables<a class="headerlink" href="#pelican-variables-db40" title="Permanent link">¶</a></h2><p>As I mentioned, we are currently overriding Pelican's output with a static template. What we want to do is to inject values known to Pelican into the template itself, be those static variables or more dynamic items like articles, tags, and images.</p><p>To do this, Pelican uses <a href="https://jinja.palletsprojects.com/en/2.11.x/">Jinja</a>, a widely adopted template engine written in Python. If you want to fully understand how to create Pelican themes, then, you need to learn Jinja. Don't worry, it's not complicated, and since Jinja uses Python you will catch up very quickly. I won't get into details about the Jinja syntax that I will use, please check out the <a href="https://jinja.palletsprojects.com/en/2.11.x/">Jinja documentation</a> if you have any doubts.</p><p>We actually already used Pelican's variables and Jinja templates when we prefixed links with <code>{{ SITEURL }}</code>. Aside from that, however, the first and simplest variable injection for our template are title and subtitle.</p><h3 id="title-dfde">Title</h3><p>The Pelican variable we are interested in is <code>SITENAME</code>, which has been initialised by the quickstart script as you can see in the configuration file</p><div class="code"><div class="title"><code>pelicanconf.py</code></div><div class="content"><div class="highlight"><pre><span class="n">SITENAME</span> <span class="o">=</span> <span class="s2">"The Analog Fox"</span>
</pre></div> </div> </div><p>We need to replace the static text with this variable three times: in the tag <code>&lt;title&gt;</code>, in the navigation bar and in the header at the top of the sidebar.</p><div class="code"><div class="title"><code>future-imperfect/templates/index.html</code></div><div class="content"><div class="highlight"><pre><span class="p"><</span><span class="nt">html</span><span class="p">></span>
<span class="p"><</span><span class="nt">head</span><span class="p">></span>
<span class="hll"> <span class="p"><</span><span class="nt">title</span><span class="p">></span><span class="cp">{{</span> <span class="nv">SITENAME</span> <span class="cp">}}</span><span class="p"></</span><span class="nt">title</span><span class="p">></span>
</span> <span class="p"><</span><span class="nt">meta</span> <span class="na">charset</span><span class="o">=</span><span class="s">"utf-8"</span> <span class="p">/></span>
<span class="p"><</span><span class="nt">meta</span> <span class="na">name</span><span class="o">=</span><span class="s">"viewport"</span> <span class="na">content</span><span class="o">=</span><span class="s">"width=device-width, initial-scale=1, user-scalable=no"</span> <span class="p">/></span>
<span class="p"><</span><span class="nt">link</span> <span class="na">rel</span><span class="o">=</span><span class="s">"stylesheet"</span> <span class="na">href</span><span class="o">=</span><span class="s">"</span><span class="cp">{{</span> <span class="nv">SITEURL</span> <span class="cp">}}</span><span class="s">/theme/css/main.css"</span> <span class="p">/></span>
<span class="p"></</span><span class="nt">head</span><span class="p">></span>
<span class="p"><</span><span class="nt">body</span> <span class="na">class</span><span class="o">=</span><span class="s">"is-preload"</span><span class="p">></span>
<span class="cm"><!-- Wrapper --></span>
<span class="p"><</span><span class="nt">div</span> <span class="na">id</span><span class="o">=</span><span class="s">"wrapper"</span><span class="p">></span>
<span class="cm"><!-- Header --></span>
<span class="p"><</span><span class="nt">header</span> <span class="na">id</span><span class="o">=</span><span class="s">"header"</span><span class="p">></span>
<span class="hll"> <span class="p"><</span><span class="nt">h1</span><span class="p">><</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">"index.html"</span><span class="p">></span><span class="cp">{{</span> <span class="nv">SITENAME</span> <span class="cp">}}</span><span class="p"></</span><span class="nt">a</span><span class="p">></</span><span class="nt">h1</span><span class="p">></span>
</span> <span class="p"><</span><span class="nt">nav</span> <span class="na">class</span><span class="o">=</span><span class="s">"links"</span><span class="p">></span>
<span class="p"><</span><span class="nt">ul</span><span class="p">></span>
<span class="p"><</span><span class="nt">li</span><span class="p">><</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">"#"</span><span class="p">></span>Lorem<span class="p"></</span><span class="nt">a</span><span class="p">></</span><span class="nt">li</span><span class="p">></span>
[...]
<span class="cm"><!-- Sidebar --></span>
<span class="p"><</span><span class="nt">section</span> <span class="na">id</span><span class="o">=</span><span class="s">"sidebar"</span><span class="p">></span>
<span class="cm"><!-- Intro --></span>
<span class="p"><</span><span class="nt">section</span> <span class="na">id</span><span class="o">=</span><span class="s">"intro"</span><span class="p">></span>
<span class="p"><</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">"#"</span> <span class="na">class</span><span class="o">=</span><span class="s">"logo"</span><span class="p">><</span><span class="nt">img</span> <span class="na">src</span><span class="o">=</span><span class="s">"</span><span class="cp">{{</span> <span class="nv">SITEURL</span> <span class="cp">}}</span><span class="s">/theme/images/logo.jpg"</span> <span class="na">alt</span><span class="o">=</span><span class="s">""</span> <span class="p">/></</span><span class="nt">a</span><span class="p">></span>
<span class="p"><</span><span class="nt">header</span><span class="p">></span>
<span class="hll"> <span class="p"><</span><span class="nt">h2</span><span class="p">></span><span class="cp">{{</span> <span class="nv">SITENAME</span> <span class="cp">}}</span><span class="p"></</span><span class="nt">h2</span><span class="p">></span>
</span> <span class="p"><</span><span class="nt">p</span><span class="p">></span>Another fine responsive site template by <span class="p"><</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">"http://html5up.net"</span><span class="p">></span>HTML5 UP<span class="p"></</span><span class="nt">a</span><span class="p">></</span><span class="nt">p</span><span class="p">></span>
<span class="p"></</span><span class="nt">header</span><span class="p">></span>
<span class="p"></</span><span class="nt">section</span><span class="p">></span>
</pre></div> </div> </div><h3 id="subtitle-1f67">Subtitle</h3><p>Pelican provides support even for the subtitle, but that wasn't filled in by the setup script for us, so we need to create the variable in the configuration file</p><div class="code"><div class="title"><code>pelicanconf.py</code></div><div class="content"><div class="highlight"><pre><span class="n">SITENAME</span> <span class="o">=</span> <span class="s2">"The Analog Fox"</span>
<span class="n">SITESUBTITLE</span> <span class="o">=</span> <span class="s2">"A great blog about old stuff"</span>
</pre></div> </div> </div><p>Once this is done we can insert the variable at the top of the sidebar, just under the title</p><div class="code"><div class="title"><code>future-imperfect/templates/index.html</code></div><div class="content"><div class="highlight"><pre> <span class="p"><</span><span class="nt">section</span> <span class="na">id</span><span class="o">=</span><span class="s">"intro"</span><span class="p">></span>
<span class="p"><</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">"#"</span> <span class="na">class</span><span class="o">=</span><span class="s">"logo"</span><span class="p">><</span><span class="nt">img</span> <span class="na">src</span><span class="o">=</span><span class="s">"</span><span class="cp">{{</span> <span class="nv">SITEURL</span> <span class="cp">}}</span><span class="s">/theme/images/logo.jpg"</span> <span class="na">alt</span><span class="o">=</span><span class="s">""</span> <span class="p">/></</span><span class="nt">a</span><span class="p">></span>
<span class="p"><</span><span class="nt">header</span><span class="p">></span>
<span class="p"><</span><span class="nt">h2</span><span class="p">></span><span class="cp">{{</span> <span class="nv">SITENAME</span> <span class="cp">}}</span><span class="p"></</span><span class="nt">h2</span><span class="p">></span>
<span class="hll"> <span class="p"><</span><span class="nt">p</span><span class="p">></span><span class="cp">{{</span> <span class="nv">SITESUBTITLE</span> <span class="cp">}}</span><span class="p"></</span><span class="nt">p</span><span class="p">></span>
</span> <span class="p"></</span><span class="nt">header</span><span class="p">></span>
<span class="p"></</span><span class="nt">section</span><span class="p">></span>
</pre></div> </div> </div><p>Marvellous! Now the page should show the title of the blog in the window header, announcing to the world the The Analog Fox is ready to take over the world of vintage!</p><p>OK, I might be a bit overexcited, but I love when plans come together ;)</p><h3 id="deep-dive-e364">Deep dive</h3><p>Pelican passes the whole configuration file to the template, together with the parsed content of the site itself, so you are free to use any variable, should you need them, or to introduce new ones (which we will do in the next section).</p><p>For now, just to familiarise with the concept, you might try to add <code>TIMEZONE</code> under the subtitle</p><div class="code"><div class="title"><code>future-imperfect/templates/index.html</code></div><div class="content"><div class="highlight"><pre> <span class="p"><</span><span class="nt">header</span><span class="p">></span>
<span class="p"><</span><span class="nt">h2</span><span class="p">></span><span class="cp">{{</span> <span class="nv">SITENAME</span> <span class="cp">}}</span><span class="p"></</span><span class="nt">h2</span><span class="p">></span>
<span class="p"><</span><span class="nt">p</span><span class="p">></span><span class="cp">{{</span> <span class="nv">SITESUBTITLE</span> <span class="cp">}}</span><span class="p"></</span><span class="nt">p</span><span class="p">></span>
<span class="p"><</span><span class="nt">p</span><span class="p">></span><span class="cp">{{</span> <span class="nv">TIMEZONE</span> <span class="cp">}}</span><span class="p"></</span><span class="nt">p</span><span class="p">></span>
<span class="p"></</span><span class="nt">header</span><span class="p">></span>
</pre></div> </div> </div><p>I don't think this specific change is really useful, but it's good to remember that all those variables are available.</p><h2 id="social-buttons-d456">Social buttons<a class="headerlink" href="#social-buttons-d456" title="Permanent link">¶</a></h2><p>The template has a section for social buttons under the sidebar, and this is a great use case for a bit of advanced usage of the configuration file.</p><p>Pelican has a native support for social links, as you can see from the <code>SOCIAL</code> variable in <code>pelicanconf.py</code>. For the sake of showing you that you are free to define custom variables in that file and use them I will however ignore it and go with something richer. The template uses nice icons to represent the links, so I'd like to include that information.</p><p>The section of the template that renders those buttons is</p><div class="code"><div class="title"><code>future-imperfect/templates/index.html</code></div><div class="content"><div class="highlight"><pre> <span class="cm"><!-- Footer --></span>
<span class="p"><</span><span class="nt">section</span> <span class="na">id</span><span class="o">=</span><span class="s">"footer"</span><span class="p">></span>
<span class="p"><</span><span class="nt">ul</span> <span class="na">class</span><span class="o">=</span><span class="s">"icons"</span><span class="p">></span>
<span class="p"><</span><span class="nt">li</span><span class="p">><</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">"#"</span> <span class="na">class</span><span class="o">=</span><span class="s">"icon brands fa-twitter"</span><span class="p">><</span><span class="nt">span</span> <span class="na">class</span><span class="o">=</span><span class="s">"label"</span><span class="p">></span>Twitter<span class="p"></</span><span class="nt">span</span><span class="p">></</span><span class="nt">a</span><span class="p">></</span><span class="nt">li</span><span class="p">></span>
<span class="p"><</span><span class="nt">li</span><span class="p">><</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">"#"</span> <span class="na">class</span><span class="o">=</span><span class="s">"icon brands fa-facebook-f"</span><span class="p">><</span><span class="nt">span</span> <span class="na">class</span><span class="o">=</span><span class="s">"label"</span><span class="p">></span>Facebook<span class="p"></</span><span class="nt">span</span><span class="p">></</span><span class="nt">a</span><span class="p">></</span><span class="nt">li</span><span class="p">></span>
<span class="p"><</span><span class="nt">li</span><span class="p">><</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">"#"</span> <span class="na">class</span><span class="o">=</span><span class="s">"icon brands fa-instagram"</span><span class="p">><</span><span class="nt">span</span> <span class="na">class</span><span class="o">=</span><span class="s">"label"</span><span class="p">></span>Instagram<span class="p"></</span><span class="nt">span</span><span class="p">></</span><span class="nt">a</span><span class="p">></</span><span class="nt">li</span><span class="p">></span>
<span class="p"><</span><span class="nt">li</span><span class="p">><</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">"#"</span> <span class="na">class</span><span class="o">=</span><span class="s">"icon solid fa-rss"</span><span class="p">><</span><span class="nt">span</span> <span class="na">class</span><span class="o">=</span><span class="s">"label"</span><span class="p">></span>RSS<span class="p"></</span><span class="nt">span</span><span class="p">></</span><span class="nt">a</span><span class="p">></</span><span class="nt">li</span><span class="p">></span>
<span class="p"><</span><span class="nt">li</span><span class="p">><</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">"#"</span> <span class="na">class</span><span class="o">=</span><span class="s">"icon solid fa-envelope"</span><span class="p">><</span><span class="nt">span</span> <span class="na">class</span><span class="o">=</span><span class="s">"label"</span><span class="p">></span>Email<span class="p"></</span><span class="nt">span</span><span class="p">></</span><span class="nt">a</span><span class="p">></</span><span class="nt">li</span><span class="p">></span>
<span class="p"></</span><span class="nt">ul</span><span class="p">></span>
<span class="p"><</span><span class="nt">p</span> <span class="na">class</span><span class="o">=</span><span class="s">"copyright"</span><span class="p">></span><span class="ni">&copy;</span> Untitled. Design: <span class="p"><</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">"http://html5up.net"</span><span class="p">></span>HTML5 UP<span class="p"></</span><span class="nt">a</span><span class="p">></span>. Images: <span class="p"><</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">"http://unsplash.com"</span><span class="p">></span>Unsplash<span class="p"></</span><span class="nt">a</span><span class="p">></span>.<span class="p"></</span><span class="nt">p</span><span class="p">></span>
<span class="p"></</span><span class="nt">section</span><span class="p">></span>
</pre></div> </div> </div><p>Lists are one of the most common patterns when writing templates, as they usually become just a simple for loop. let's start writing down the data, then we will learn how to render the buttons.</p><p>As I mentioned, I created a new variable <code>CONTACTS</code></p><div class="code"><div class="title"><code>pelicanconf.py</code></div><div class="content"><div class="highlight"><pre><span class="c1"># Social widget</span>
<span class="n">SOCIAL</span> <span class="o">=</span> <span class="p">(</span>
<span class="p">(</span><span class="s2">"You can add links in your config file"</span><span class="p">,</span> <span class="s2">"#"</span><span class="p">),</span>
<span class="p">(</span><span class="s2">"Another social link"</span><span class="p">,</span> <span class="s2">"#"</span><span class="p">),</span>
<span class="p">)</span>
<span class="hll"><span class="n">CONTACTS</span> <span class="o">=</span> <span class="p">[</span>
</span><span class="hll"> <span class="p">(</span><span class="s2">"Twitter"</span><span class="p">,</span> <span class="s2">"twitter"</span><span class="p">,</span> <span class="s2">"https://twitter.com/theanalogfox"</span><span class="p">),</span>
</span><span class="hll"> <span class="p">(</span><span class="s2">"Facebook"</span><span class="p">,</span> <span class="s2">"facebook-f"</span><span class="p">,</span> <span class="s2">"https://facebook.com/theanalogfox"</span><span class="p">),</span>
</span><span class="hll"> <span class="p">(</span><span class="s2">"Instagram"</span><span class="p">,</span> <span class="s2">"instagram"</span><span class="p">,</span> <span class="s2">"https://www.instagram.com/theanalogfox/"</span><span class="p">),</span>
</span><span class="hll"> <span class="p">(</span><span class="s2">"Email"</span><span class="p">,</span> <span class="s2">"envelope"</span><span class="p">,</span> <span class="s2">"info@theanalogfox.com"</span><span class="p">),</span>
</span><span class="hll"><span class="p">]</span>
</span>
<span class="n">DEFAULT_PAGINATION</span> <span class="o">=</span> <span class="mi">3</span>
</pre></div> </div> </div><p>that is a list of tuples, each one including the title of the button, the name of the icon (Font Awesome), and the link itself. Now we can replace the snippet of code above with this</p><div class="code"><div class="title"><code>future-imperfect/templates/index.html</code></div><div class="content"><div class="highlight"><pre> <span class="cm"><!-- Footer --></span>
<span class="p"><</span><span class="nt">section</span> <span class="na">id</span><span class="o">=</span><span class="s">"footer"</span><span class="p">></span>
<span class="p"><</span><span class="nt">ul</span> <span class="na">class</span><span class="o">=</span><span class="s">"icons"</span><span class="p">></span>
<span class="hll"> <span class="cp">{%</span> <span class="k">for</span> <span class="nv">name</span><span class="o">,</span> <span class="nv">icon</span><span class="o">,</span> <span class="nv">link</span> <span class="k">in</span> <span class="nv">CONTACTS</span> <span class="cp">%}</span>
</span><span class="hll"> <span class="p"><</span><span class="nt">li</span><span class="p">><</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">"</span><span class="cp">{{</span> <span class="nv">link</span> <span class="cp">}}</span><span class="s">"</span> <span class="na">class</span><span class="o">=</span><span class="s">"icon brands fa-</span><span class="cp">{{</span> <span class="nv">icon</span> <span class="cp">}}</span><span class="s">"</span><span class="p">><</span><span class="nt">span</span> <span class="na">class</span><span class="o">=</span><span class="s">"label"</span><span class="p">></span><span class="cp">{{</span> <span class="nv">name</span> <span class="cp">}}</span><span class="p"></</span><span class="nt">span</span><span class="p">></</span><span class="nt">a</span><span class="p">></</span><span class="nt">li</span><span class="p">></span>
</span><span class="hll"> <span class="cp">{%</span> <span class="k">endfor</span> <span class="cp">%}</span>
</span> <span class="p"></</span><span class="nt">ul</span><span class="p">></span>
<span class="p"><</span><span class="nt">p</span> <span class="na">class</span><span class="o">=</span><span class="s">"copyright"</span><span class="p">></span><span class="ni">&copy;</span> Untitled. Design: <span class="p"><</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">"http://html5up.net"</span><span class="p">></span>HTML5 UP<span class="p"></</span><span class="nt">a</span><span class="p">></span>. Images: <span class="p"><</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">"http://unsplash.com"</span><span class="p">></span>Unsplash<span class="p"></</span><span class="nt">a</span><span class="p">></span>.<span class="p"></</span><span class="nt">p</span><span class="p">></span>
<span class="p"></</span><span class="nt">section</span><span class="p">></span>
</pre></div> </div> </div><p>As you can see, the core of the snippet is a <code>for</code> loop that uses Python's unpacking to assign <code>name</code>, <code>icon</code>, and <code>link</code>. The variables are then used directly in the HTML as we did before. Remember that Jinja doesn't understand HTML, it just blindly replaces the variables in a text file, which allows us to perform nice tricks like <code>fa-{{ icon }}</code> to use the right icon for each social button.</p><h2 id="articles-16fa">Articles<a class="headerlink" href="#articles-16fa" title="Permanent link">¶</a></h2><p>Now that we introduced loops and variables we have all the tools we need to work on the two lists of articles. Let's first change the list in the main body of the page, the one in the sidebar will then receive the very same treatment.</p><p>First of all, I reduced the static list of posts to a single one</p><div class="code"><div class="title"><code>future-imperfect/templates/index.html</code></div><div class="content"><div class="highlight"><pre> <span class="cm"><!-- Main --></span>
<span class="p"><</span><span class="nt">div</span> <span class="na">id</span><span class="o">=</span><span class="s">"main"</span><span class="p">></span>
<span class="cm"><!-- Post --></span>
<span class="p"><</span><span class="nt">article</span> <span class="na">class</span><span class="o">=</span><span class="s">"post"</span><span class="p">></span>
<span class="p"><</span><span class="nt">header</span><span class="p">></span>
<span class="p"><</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">"title"</span><span class="p">></span>
<span class="p"><</span><span class="nt">h2</span><span class="p">><</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">"single.html"</span><span class="p">></span>Magna sed adipiscing<span class="p"></</span><span class="nt">a</span><span class="p">></</span><span class="nt">h2</span><span class="p">></span>
<span class="p"><</span><span class="nt">p</span><span class="p">></span>Lorem ipsum dolor amet nullam consequat etiam feugiat<span class="p"></</span><span class="nt">p</span><span class="p">></span>
<span class="p"></</span><span class="nt">div</span><span class="p">></span>
<span class="p"><</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">"meta"</span><span class="p">></span>
<span class="p"><</span><span class="nt">time</span> <span class="na">class</span><span class="o">=</span><span class="s">"published"</span> <span class="na">datetime</span><span class="o">=</span><span class="s">"2015-11-01"</span><span class="p">></span>November 1, 2015<span class="p"></</span><span class="nt">time</span><span class="p">></span>
<span class="p"><</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">"#"</span> <span class="na">class</span><span class="o">=</span><span class="s">"author"</span><span class="p">><</span><span class="nt">span</span> <span class="na">class</span><span class="o">=</span><span class="s">"name"</span><span class="p">></span>Jane Doe<span class="p"></</span><span class="nt">span</span><span class="p">><</span><span class="nt">img</span> <span class="na">src</span><span class="o">=</span><span class="s">"</span><span class="cp">{{</span> <span class="nv">SITEURL</span> <span class="cp">}}</span><span class="s">/theme/images/avatar.jpg"</span> <span class="na">alt</span><span class="o">=</span><span class="s">""</span> <span class="p">/></</span><span class="nt">a</span><span class="p">></span>
<span class="p"></</span><span class="nt">div</span><span class="p">></span>
<span class="p"></</span><span class="nt">header</span><span class="p">></span>
<span class="p"><</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">"single.html"</span> <span class="na">class</span><span class="o">=</span><span class="s">"image featured"</span><span class="p">><</span><span class="nt">img</span> <span class="na">src</span><span class="o">=</span><span class="s">"</span><span class="cp">{{</span> <span class="nv">SITEURL</span> <span class="cp">}}</span><span class="s">/theme/images/pic01.jpg"</span> <span class="na">alt</span><span class="o">=</span><span class="s">""</span> <span class="p">/></</span><span class="nt">a</span><span class="p">></span>
<span class="p"><</span><span class="nt">p</span><span class="p">></span>Mauris neque quam, fermentum ut nisl vitae, convallis maximus nisl. Sed mattis nunc id lorem euismod placerat. Vivamus porttitor magna enim, ac accumsan tortor cursus at. Phasellus sed ultricies mi non congue ullam corper. Praesent tincidunt sed tellus ut rutrum. Sed vitae justo condimentum, porta lectus vitae, ultricies congue gravida diam non fringilla.<span class="p"></</span><span class="nt">p</span><span class="p">></span>
<span class="p"><</span><span class="nt">footer</span><span class="p">></span>
<span class="p"><</span><span class="nt">ul</span> <span class="na">class</span><span class="o">=</span><span class="s">"actions"</span><span class="p">></span>
<span class="p"><</span><span class="nt">li</span><span class="p">><</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">"single.html"</span> <span class="na">class</span><span class="o">=</span><span class="s">"button large"</span><span class="p">></span>Continue Reading<span class="p"></</span><span class="nt">a</span><span class="p">></</span><span class="nt">li</span><span class="p">></span>
<span class="p"></</span><span class="nt">ul</span><span class="p">></span>
<span class="p"><</span><span class="nt">ul</span> <span class="na">class</span><span class="o">=</span><span class="s">"stats"</span><span class="p">></span>
<span class="p"><</span><span class="nt">li</span><span class="p">><</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">"#"</span><span class="p">></span>General<span class="p"></</span><span class="nt">a</span><span class="p">></</span><span class="nt">li</span><span class="p">></span>
<span class="p"><</span><span class="nt">li</span><span class="p">><</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">"#"</span> <span class="na">class</span><span class="o">=</span><span class="s">"icon solid fa-heart"</span><span class="p">></span>28<span class="p"></</span><span class="nt">a</span><span class="p">></</span><span class="nt">li</span><span class="p">></span>
<span class="p"><</span><span class="nt">li</span><span class="p">><</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">"#"</span> <span class="na">class</span><span class="o">=</span><span class="s">"icon solid fa-comment"</span><span class="p">></span>128<span class="p"></</span><span class="nt">a</span><span class="p">></</span><span class="nt">li</span><span class="p">></span>
<span class="p"></</span><span class="nt">ul</span><span class="p">></span>
<span class="p"></</span><span class="nt">footer</span><span class="p">></span>
<span class="p"></</span><span class="nt">article</span><span class="p">></span>
<span class="cm"><!-- Pagination --></span>
<span class="p"><</span><span class="nt">ul</span> <span class="na">class</span><span class="o">=</span><span class="s">"actions pagination"</span><span class="p">></span>
<span class="p"><</span><span class="nt">li</span><span class="p">><</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">""</span> <span class="na">class</span><span class="o">=</span><span class="s">"disabled button large previous"</span><span class="p">></span>Previous Page<span class="p"></</span><span class="nt">a</span><span class="p">></</span><span class="nt">li</span><span class="p">></span>
<span class="p"><</span><span class="nt">li</span><span class="p">><</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">"#"</span> <span class="na">class</span><span class="o">=</span><span class="s">"button large next"</span><span class="p">></span>Next Page<span class="p"></</span><span class="nt">a</span><span class="p">></</span><span class="nt">li</span><span class="p">></span>
<span class="p"></</span><span class="nt">ul</span><span class="p">></span>
<span class="p"></</span><span class="nt">div</span><span class="p">></span>
</pre></div> </div> </div><p>Please note that your content will be slightly different as it has been randomly generated.</p><p>The list of Pelican variables we can access is available at <a href="https://docs.getpelican.com/en/latest/themes.html#index-html">https://docs.getpelican.com/en/latest/themes.html#index-html</a> (variables for the page <code>index.html</code>) and <a href="https://docs.getpelican.com/en/latest/themes.html#article">https://docs.getpelican.com/en/latest/themes.html#article</a> (attributes of <code>Article</code> objects).</p><div class="code"><div class="title"><code>future-imperfect/templates/index.html</code></div><div class="content"><div class="highlight"><pre><span class="hll"> <span class="cp">{%</span> <span class="k">for</span> <span class="nv">article</span> <span class="k">in</span> <span class="nv">articles</span> <span class="cp">%}</span>
</span> <span class="cm"><!-- Post --></span>
<span class="p"><</span><span class="nt">article</span> <span class="na">class</span><span class="o">=</span><span class="s">"post"</span><span class="p">></span>
<span class="p"><</span><span class="nt">header</span><span class="p">></span>
<span class="p"><</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">"title"</span><span class="p">></span>
<span class="hll"> <span class="p"><</span><span class="nt">h2</span><span class="p">><</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">"single.html"</span><span class="p">></span><span class="cp">{{</span> <span class="nv">article.title</span> <span class="cp">}}</span><span class="p"></</span><span class="nt">a</span><span class="p">></</span><span class="nt">h2</span><span class="p">></span>
</span><span class="hll"> <span class="p"><</span><span class="nt">p</span><span class="p">></span><span class="cp">{{</span> <span class="nv">article.summary</span> <span class="cp">}}</span><span class="p"></</span><span class="nt">p</span><span class="p">></span>
</span> <span class="p"></</span><span class="nt">div</span><span class="p">></span>
<span class="p"><</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">"meta"</span><span class="p">></span>
<span class="hll"> <span class="p"><</span><span class="nt">time</span> <span class="na">class</span><span class="o">=</span><span class="s">"published"</span> <span class="na">datetime</span><span class="o">=</span><span class="s">"</span><span class="cp">{{</span> <span class="nv">article.date</span> <span class="o">|</span> <span class="nf">strftime</span><span class="o">(</span><span class="s1">'%Y-%m-%d'</span><span class="o">)</span> <span class="cp">}}</span><span class="s">"</span><span class="p">></span><span class="cp">{{</span> <span class="nv">article.date</span> <span class="o">|</span> <span class="nf">strftime</span><span class="o">(</span><span class="s1">'%b %-d, %Y'</span><span class="o">)</span> <span class="cp">}}</span><span class="p"></</span><span class="nt">time</span><span class="p">></span>
</span><span class="hll"> <span class="p"><</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">"#"</span> <span class="na">class</span><span class="o">=</span><span class="s">"author"</span><span class="p">><</span><span class="nt">span</span> <span class="na">class</span><span class="o">=</span><span class="s">"name"</span><span class="p">></span><span class="cp">{{</span> <span class="nv">article.author</span> <span class="cp">}}</span><span class="p"></</span><span class="nt">span</span><span class="p">><</span><span class="nt">img</span> <span class="na">src</span><span class="o">=</span><span class="s">"</span><span class="cp">{{</span> <span class="nv">SITEURL</span> <span class="cp">}}</span><span class="s">/theme/images/avatar.jpg"</span> <span class="na">alt</span><span class="o">=</span><span class="s">""</span> <span class="p">/></</span><span class="nt">a</span><span class="p">></span>
</span> <span class="p"></</span><span class="nt">div</span><span class="p">></span>
<span class="p"></</span><span class="nt">header</span><span class="p">></span>
<span class="p"><</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">"single.html"</span> <span class="na">class</span><span class="o">=</span><span class="s">"image featured"</span><span class="p">><</span><span class="nt">img</span> <span class="na">src</span><span class="o">=</span><span class="s">"</span><span class="cp">{{</span> <span class="nv">SITEURL</span> <span class="cp">}}</span><span class="s">/theme/images/pic01.jpg"</span> <span class="na">alt</span><span class="o">=</span><span class="s">""</span> <span class="p">/></</span><span class="nt">a</span><span class="p">></span>
<span class="hll"> <span class="cp">{{</span> <span class="nv">article.content</span> <span class="cp">}}</span>
</span> <span class="p"><</span><span class="nt">footer</span><span class="p">></span>
<span class="p"><</span><span class="nt">ul</span> <span class="na">class</span><span class="o">=</span><span class="s">"actions"</span><span class="p">></span>
<span class="p"><</span><span class="nt">li</span><span class="p">><</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">"single.html"</span> <span class="na">class</span><span class="o">=</span><span class="s">"button large"</span><span class="p">></span>Continue Reading<span class="p"></</span><span class="nt">a</span><span class="p">></</span><span class="nt">li</span><span class="p">></span>
<span class="p"></</span><span class="nt">ul</span><span class="p">></span>
<span class="p"><</span><span class="nt">ul</span> <span class="na">class</span><span class="o">=</span><span class="s">"stats"</span><span class="p">></span>
<span class="hll"> <span class="cp">{%</span> <span class="k">for</span> <span class="nv">tag</span> <span class="k">in</span> <span class="nv">article.tags</span> <span class="cp">%}</span>
</span><span class="hll"> <span class="p"><</span><span class="nt">li</span><span class="p">><</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">"#"</span><span class="p">></span><span class="cp">{{</span> <span class="nv">tag.name</span> <span class="cp">}}</span><span class="p"></</span><span class="nt">a</span><span class="p">></</span><span class="nt">li</span><span class="p">></span>
</span><span class="hll"> <span class="cp">{%</span> <span class="k">endfor</span> <span class="cp">%}</span>
</span> <span class="p"></</span><span class="nt">ul</span><span class="p">></span>
<span class="p"></</span><span class="nt">footer</span><span class="p">></span>
<span class="p"></</span><span class="nt">article</span><span class="p">></span>
<span class="hll"> <span class="cp">{%</span> <span class="k">endfor</span> <span class="cp">%}</span>
</pre></div> </div> </div><p>As you can see we can just loop over the page variable <code>articles</code> and read the attributes of object just like we usually do in Python, for example with <code>{{ article.title }}</code> or <code>{{ article.summary }}</code>.</p><p>Jinja filters are very powerful, and as you see I used them twice with dates to give them different formats. One for the internal representation of time <code>{{ article.date | strftime('%Y-%m-%d') }}</code> and one is the more visually pleasant (<code>{{ article.date | strftime('%b %-d, %Y') }}</code>). I don't normally use the American date format, but as the template did I kept it as a good example of what you can do with Jinja filters.</p><p>Last, you can nest for loops in other for loops, as I did with tags. You can see the internal structure of tags <a href="https://docs.getpelican.com/en/latest/themes.html#author-category-tag">in the documentation</a>. Please note that the string representation of tags (and other objects in Pelican) is the attribute <code>name</code>, so we might write</p><div class="code"><div class="content"><div class="highlight"><pre> <span class="cp">{%</span> <span class="k">for</span> <span class="nv">tag</span> <span class="k">in</span> <span class="nv">article.tags</span> <span class="cp">%}</span>
<span class="hll"> <span class="p"><</span><span class="nt">li</span><span class="p">><</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">"#"</span><span class="p">></span><span class="cp">{{</span> <span class="nv">tag</span> <span class="cp">}}</span><span class="p"></</span><span class="nt">a</span><span class="p">></</span><span class="nt">li</span><span class="p">></span>
</span> <span class="cp">{%</span> <span class="k">endfor</span> <span class="cp">%}</span>
</pre></div> </div> </div><p>and it would return the same output.</p><p>A note about the content of the article. As you can see <code>{{ article.content }}</code> prints the full article, so if you want to print a preview you need to truncate it. Unfortunately you can't just write something like <code>{{ article.content[:600] }}</code> to print 600 characters. Remember that Jinja works on the output of the readers already, which means that <code>article. content</code> is already HTML, and if you arbitrarily truncate it you leave some tags open, which disrupts the rendering of the page.</p><p>At the end of the post I will show you how you can easily solve this in Pelican, once we have a dedicated page for each article.</p><h2 id="pagination-1e5d">Pagination<a class="headerlink" href="#pagination-1e5d" title="Permanent link">¶</a></h2><p>What we did in the previous section prints all the articles in the blog on the same page. This is clearly not acceptable as the number of articles increases, and the standard solution for this is <em>pagination</em>.</p><p>Pelican fully supports it, and if you remember we set it up when we run <code>pelican-quickstart</code>. You can see the current number of articles per page in <code>pelicanconf.py</code></p><div class="code"><div class="content"><div class="highlight"><pre><span class="n">DEFAULT_PAGINATION</span> <span class="o">=</span> <span class="mi">3</span>
</pre></div> </div> </div><p>To leverage pagination we first need to replace the variable <code>articles</code> with <code>articles_page.object_list</code></p><div class="code"><div class="title"><code>future-imperfect/templates/index.html</code></div><div class="content"><div class="highlight"><pre><span class="hll"> <span class="cp">{%</span> <span class="k">for</span> <span class="nv">article</span> <span class="k">in</span> <span class="nv">articles_page.object_list</span> <span class="cp">%}</span>
</span> <span class="cm"><!-- Post --></span>
<span class="p"><</span><span class="nt">article</span> <span class="na">class</span><span class="o">=</span><span class="s">"post"</span><span class="p">></span>
<span class="p"><</span><span class="nt">header</span><span class="p">></span>
<span class="p"><</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">"title"</span><span class="p">></span>
<span class="p"><</span><span class="nt">h2</span><span class="p">><</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">"single.html"</span><span class="p">></span><span class="cp">{{</span> <span class="nv">article.title</span> <span class="cp">}}</span><span class="p"></</span><span class="nt">a</span><span class="p">></</span><span class="nt">h2</span><span class="p">></span>
<span class="p"><</span><span class="nt">p</span><span class="p">></span><span class="cp">{{</span> <span class="nv">article.summary</span> <span class="cp">}}</span><span class="p"></</span><span class="nt">p</span><span class="p">></span>
</pre></div> </div> </div><p>If you render the page in the browser now you'll see that it shows only the last 3 posts, which corresponds to the value of <code>DEFAULT_PAGINATION</code>. If you want you can try to change it and see it affecting the page.</p><p>To use pagination we also need to configure navigation buttons. The template already includes them after all the articles in the main body.</p><div class="code"><div class="content"><div class="highlight"><pre> <span class="cm"><!-- Pagination --></span>
<span class="p"><</span><span class="nt">ul</span> <span class="na">class</span><span class="o">=</span><span class="s">"actions pagination"</span><span class="p">></span>
<span class="p"><</span><span class="nt">li</span><span class="p">><</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">""</span> <span class="na">class</span><span class="o">=</span><span class="s">"disabled button large previous"</span><span class="p">></span>Previous Page<span class="p"></</span><span class="nt">a</span><span class="p">></</span><span class="nt">li</span><span class="p">></span>
<span class="p"><</span><span class="nt">li</span><span class="p">><</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">"#"</span> <span class="na">class</span><span class="o">=</span><span class="s">"button large next"</span><span class="p">></span>Next Page<span class="p"></</span><span class="nt">a</span><span class="p">></</span><span class="nt">li</span><span class="p">></span>
<span class="p"></</span><span class="nt">ul</span><span class="p">></span>
</pre></div> </div> </div><p>We have three different cases when it comes to pagination. The first page should grey out or remove the "Previous page" button, the last page should do the same with the "Next page" button, and any page between the two should show both.</p><p>We can achieve it with the following code</p><div class="code"><div class="title"><code>future-imperfect/templates/index.html</code></div><div class="content"><div class="highlight"><pre> <span class="cm"><!-- Pagination --></span>
<span class="p"><</span><span class="nt">ul</span> <span class="na">class</span><span class="o">=</span><span class="s">"actions pagination"</span><span class="p">></span>
<span class="cp">{%</span> <span class="k">if</span> <span class="nv">articles_page.has_previous</span><span class="o">()</span> <span class="cp">%}</span>
<span class="p"><</span><span class="nt">li</span><span class="p">><</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">"/</span><span class="cp">{{</span> <span class="nv">articles_previous_page.url</span> <span class="cp">}}</span><span class="s">"</span> <span class="na">class</span><span class="o">=</span><span class="s">"button large previous"</span><span class="p">></span>Previous Page<span class="p"></</span><span class="nt">a</span><span class="p">></</span><span class="nt">li</span><span class="p">></span>
<span class="cp">{%</span> <span class="k">else</span> <span class="cp">%}</span>
<span class="p"><</span><span class="nt">li</span><span class="p">><</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">""</span> <span class="na">class</span><span class="o">=</span><span class="s">"disabled button large previous"</span><span class="p">></span>Previous Page<span class="p"></</span><span class="nt">a</span><span class="p">></</span><span class="nt">li</span><span class="p">></span>
<span class="cp">{%</span> <span class="k">endif</span> <span class="cp">%}</span>
<span class="cp">{%</span> <span class="k">if</span> <span class="nv">articles_page.has_next</span><span class="o">()</span> <span class="cp">%}</span>
<span class="p"><</span><span class="nt">li</span><span class="p">><</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">"/</span><span class="cp">{{</span> <span class="nv">articles_next_page.url</span> <span class="cp">}}</span><span class="s">"</span> <span class="na">class</span><span class="o">=</span><span class="s">"button large next"</span><span class="p">></span>Next Page<span class="p"></</span><span class="nt">a</span><span class="p">></</span><span class="nt">li</span><span class="p">></span>
<span class="cp">{%</span> <span class="k">else</span> <span class="cp">%}</span>
<span class="p"><</span><span class="nt">li</span><span class="p">><</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">"#"</span> <span class="na">class</span><span class="o">=</span><span class="s">"disabled button large next"</span><span class="p">></span>Next Page<span class="p"></</span><span class="nt">a</span><span class="p">></</span><span class="nt">li</span><span class="p">></span>
<span class="cp">{%</span> <span class="k">endif</span> <span class="cp">%}</span>
<span class="p"></</span><span class="nt">ul</span><span class="p">></span>
</pre></div> </div> </div><p>The two functions <code>articles_page.has_previous()</code> and <code>articles_page.has_next()</code> can be used to know if there are pages before of after the current one, and if not we can use the class <code>disabled</code> to grey out the button. The link to the previous or next page is provided by <code>articles_previous_page.url</code> and <code>articles_next_page.url</code> respectively. Again, remember that you can learn everything about all these variables reading <a href="https://docs.getpelican.com/en/latest/themes.html">Pelican's documentation on themes</a>.</p><p>Render the page in the browser and you will see that the "Next page" button leads to <a href="http://localhost:8000/index2.html">http://localhost:8000/index2.html</a>, which is the second page of articles. Indeed, if you click it, you will see articles from 17 to 15, and so on until the last page of articles <a href="http://localhost:8001/index7.html">http://localhost:8001/index7.html</a> that contains the first and the secodn articles of the blog (if you generated 20 articles at the beginning as I did).</p><h2 id="slicing-6582">Slicing<a class="headerlink" href="#slicing-6582" title="Permanent link">¶</a></h2><p>The sidebar is usually the best place to show a fixed set of posts like latest ones. We can easily achieve this slicing the list of articles. To do this let's first reduce the number of mini posts to one, so that we can introduce a loop</p><div class="code"><div class="title"><code>future-imperfect/templates/index.html</code></div><div class="content"><div class="highlight"><pre> <span class="cm"><!-- Mini Posts --></span>
<span class="p"><</span><span class="nt">section</span><span class="p">></span>
<span class="p"><</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">"mini-posts"</span><span class="p">></span>
<span class="cm"><!-- Mini Post --></span>
<span class="p"><</span><span class="nt">article</span> <span class="na">class</span><span class="o">=</span><span class="s">"mini-post"</span><span class="p">></span>
<span class="p"><</span><span class="nt">header</span><span class="p">></span>
<span class="p"><</span><span class="nt">h3</span><span class="p">><</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">"single.html"</span><span class="p">></span>Vitae sed condimentum<span class="p"></</span><span class="nt">a</span><span class="p">></</span><span class="nt">h3</span><span class="p">></span>
<span class="p"><</span><span class="nt">time</span> <span class="na">class</span><span class="o">=</span><span class="s">"published"</span> <span class="na">datetime</span><span class="o">=</span><span class="s">"2015-10-20"</span><span class="p">></span>October 20, 2015<span class="p"></</span><span class="nt">time</span><span class="p">></span>
<span class="p"><</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">"#"</span> <span class="na">class</span><span class="o">=</span><span class="s">"author"</span><span class="p">><</span><span class="nt">img</span> <span class="na">src</span><span class="o">=</span><span class="s">"</span><span class="cp">{{</span> <span class="nv">SITEURL</span> <span class="cp">}}</span><span class="s">/theme/images/avatar.jpg"</span> <span class="na">alt</span><span class="o">=</span><span class="s">""</span> <span class="p">/></</span><span class="nt">a</span><span class="p">></span>
<span class="p"></</span><span class="nt">header</span><span class="p">></span>
<span class="p"><</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">"single.html"</span> <span class="na">class</span><span class="o">=</span><span class="s">"image"</span><span class="p">><</span><span class="nt">img</span> <span class="na">src</span><span class="o">=</span><span class="s">"</span><span class="cp">{{</span> <span class="nv">SITEURL</span> <span class="cp">}}</span><span class="s">/theme/images/pic04.jpg"</span> <span class="na">alt</span><span class="o">=</span><span class="s">""</span> <span class="p">/></</span><span class="nt">a</span><span class="p">></span>
<span class="p"></</span><span class="nt">article</span><span class="p">></span>
<span class="p"></</span><span class="nt">div</span><span class="p">></span>
<span class="p"></</span><span class="nt">section</span><span class="p">></span>
</pre></div> </div> </div><p>We can show the last 4 articles with this simple sintax</p><div class="code"><div class="title"><code>future-imperfect/templates/index.html</code></div><div class="content"><div class="highlight"><pre> <span class="cm"><!-- Mini Posts --></span>
<span class="p"><</span><span class="nt">section</span><span class="p">></span>
<span class="p"><</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">"mini-posts"</span><span class="p">></span>
<span class="hll"> <span class="cp">{%</span> <span class="k">for</span> <span class="nv">article</span> <span class="k">in</span> <span class="nv">articles</span><span class="o">[:</span><span class="m">4</span><span class="o">]</span> <span class="cp">%}</span>
</span> <span class="cm"><!-- Mini Post --></span>
<span class="p"><</span><span class="nt">article</span> <span class="na">class</span><span class="o">=</span><span class="s">"mini-post"</span><span class="p">></span>
<span class="p"><</span><span class="nt">header</span><span class="p">></span>
<span class="p"><</span><span class="nt">h3</span><span class="p">><</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">"single.html"</span><span class="p">></span>Vitae sed condimentum<span class="p"></</span><span class="nt">a</span><span class="p">></</span><span class="nt">h3</span><span class="p">></span>
<span class="p"><</span><span class="nt">time</span> <span class="na">class</span><span class="o">=</span><span class="s">"published"</span> <span class="na">datetime</span><span class="o">=</span><span class="s">"2015-10-20"</span><span class="p">></span>October 20, 2015<span class="p"></</span><span class="nt">time</span><span class="p">></span>
<span class="p"><</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">"#"</span> <span class="na">class</span><span class="o">=</span><span class="s">"author"</span><span class="p">><</span><span class="nt">img</span> <span class="na">src</span><span class="o">=</span><span class="s">"</span><span class="cp">{{</span> <span class="nv">SITEURL</span> <span class="cp">}}</span><span class="s">/theme/images/avatar.jpg"</span> <span class="na">alt</span><span class="o">=</span><span class="s">""</span> <span class="p">/></</span><span class="nt">a</span><span class="p">></span>
<span class="p"></</span><span class="nt">header</span><span class="p">></span>
<span class="p"><</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">"single.html"</span> <span class="na">class</span><span class="o">=</span><span class="s">"image"</span><span class="p">><</span><span class="nt">img</span> <span class="na">src</span><span class="o">=</span><span class="s">"</span><span class="cp">{{</span> <span class="nv">SITEURL</span> <span class="cp">}}</span><span class="s">/theme/images/pic04.jpg"</span> <span class="na">alt</span><span class="o">=</span><span class="s">""</span> <span class="p">/></</span><span class="nt">a</span><span class="p">></span>
<span class="p"></</span><span class="nt">article</span><span class="p">></span>
<span class="hll"> <span class="cp">{%</span> <span class="k">endfor</span> <span class="cp">%}</span>
</span>
<span class="p"></</span><span class="nt">div</span><span class="p">></span>
<span class="p"></</span><span class="nt">section</span><span class="p">></span>
</pre></div> </div> </div><p>which will print the same static article 4 times because we are not using Pelican's variables yet. Applying the same changes we introduced for the main list of articles we finally get</p><div class="code"><div class="title"><code>future-imperfect/templates/index.html</code></div><div class="content"><div class="highlight"><pre> <span class="cm"><!-- Mini Posts --></span>
<span class="p"><</span><span class="nt">section</span><span class="p">></span>
<span class="p"><</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">"mini-posts"</span><span class="p">></span>
<span class="cp">{%</span> <span class="k">for</span> <span class="nv">article</span> <span class="k">in</span> <span class="nv">articles</span><span class="o">[:</span><span class="m">4</span><span class="o">]</span> <span class="cp">%}</span>
<span class="cm"><!-- Mini Post --></span>
<span class="p"><</span><span class="nt">article</span> <span class="na">class</span><span class="o">=</span><span class="s">"mini-post"</span><span class="p">></span>
<span class="p"><</span><span class="nt">header</span><span class="p">></span>
<span class="hll"> <span class="p"><</span><span class="nt">h3</span><span class="p">><</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">"single.html"</span><span class="p">></span><span class="cp">{{</span> <span class="nv">article.title</span> <span class="cp">}}</span><span class="p"></</span><span class="nt">a</span><span class="p">></</span><span class="nt">h3</span><span class="p">></span>
</span><span class="hll"> <span class="p"><</span><span class="nt">time</span> <span class="na">class</span><span class="o">=</span><span class="s">"published"</span> <span class="na">datetime</span><span class="o">=</span><span class="s">"</span><span class="cp">{{</span> <span class="nv">article.date</span> <span class="o">|</span> <span class="nf">strftime</span><span class="o">(</span><span class="s1">'%Y-%m-%d'</span><span class="o">)</span> <span class="cp">}}</span><span class="s">"</span><span class="p">></span><span class="cp">{{</span> <span class="nv">article.date</span> <span class="o">|</span> <span class="nf">strftime</span><span class="o">(</span><span class="s1">'%b %-d, %Y'</span><span class="o">)</span> <span class="cp">}}</span><span class="p"></</span><span class="nt">time</span><span class="p">></span>
</span> <span class="p"><</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">"#"</span> <span class="na">class</span><span class="o">=</span><span class="s">"author"</span><span class="p">><</span><span class="nt">img</span> <span class="na">src</span><span class="o">=</span><span class="s">"</span><span class="cp">{{</span> <span class="nv">SITEURL</span> <span class="cp">}}</span><span class="s">/theme/images/avatar.jpg"</span> <span class="na">alt</span><span class="o">=</span><span class="s">""</span> <span class="p">/></</span><span class="nt">a</span><span class="p">></span>
<span class="p"></</span><span class="nt">header</span><span class="p">></span>
<span class="p"><</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">"single.html"</span> <span class="na">class</span><span class="o">=</span><span class="s">"image"</span><span class="p">><</span><span class="nt">img</span> <span class="na">src</span><span class="o">=</span><span class="s">"</span><span class="cp">{{</span> <span class="nv">SITEURL</span> <span class="cp">}}</span><span class="s">/theme/images/pic04.jpg"</span> <span class="na">alt</span><span class="o">=</span><span class="s">""</span> <span class="p">/></</span><span class="nt">a</span><span class="p">></span>
<span class="p"></</span><span class="nt">article</span><span class="p">></span>
<span class="cp">{%</span> <span class="k">endfor</span> <span class="cp">%}</span>
<span class="p"></</span><span class="nt">div</span><span class="p">></span>
<span class="p"></</span><span class="nt">section</span><span class="p">></span>
</pre></div> </div> </div><p>And now you will see the proper titles and dates. Please note that this loop depends on <code>articles</code>, which doesn't change from page to page, so this list will be immutable across the blog.</p><h2 id="pictures-436b">Pictures<a class="headerlink" href="#pictures-436b" title="Permanent link">¶</a></h2><p>The script that created demo articles downloaded an image for each article, that can be used as featured image. There are many way to manage images in a website and I won't dive into that particular subject here. I will only show you a basic way to serve images that are not static, but part of the content.</p><p>The images are stored in <code>content/images</code> and this is also an arbitrary decision. The only thing you need to keep in mind is that Pelican's root is usually set in the directory <code>content</code>, so if you place files elsewhere it might be complicated to reach them.</p><p>Through the automated script that we used to generate content we wrote a specific metadata in each article, with the name of the relative image. For example</p><div class="code"><div class="title"><code>content/post01.markdown</code></div><div class="content"><div class="highlight"><pre>Title: A sample article 01
Date: 2021-03-01
Category: News
Tags: tag6,tag11,tag8
<span class="hll">Image: post01.jpg
</span>Summary: Summary of post 01
[...]
</pre></div> </div> </div><p>This shows you that you can add whatever metadata you want to your posts and have them loaded into the object <code>article</code>. To show the image we just need to load the correct file instead of the placeholder, both in the main list</p><div class="code"><div class="title"><code>future-imperfect/templates/index.html</code></div><div class="content"><div class="highlight"><pre> <span class="cp">{%</span> <span class="k">for</span> <span class="nv">article</span> <span class="k">in</span> <span class="nv">articles_page.object_list</span> <span class="cp">%}</span>
<span class="cm"><!-- Post --></span>
<span class="p"><</span><span class="nt">article</span> <span class="na">class</span><span class="o">=</span><span class="s">"post"</span><span class="p">></span>
<span class="p"><</span><span class="nt">header</span><span class="p">></span>
<span class="p"><</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">"title"</span><span class="p">></span>
<span class="p"><</span><span class="nt">h2</span><span class="p">><</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">"single.html"</span><span class="p">></span><span class="cp">{{</span> <span class="nv">article.title</span> <span class="cp">}}</span><span class="p"></</span><span class="nt">a</span><span class="p">></</span><span class="nt">h2</span><span class="p">></span>
<span class="p"><</span><span class="nt">p</span><span class="p">></span><span class="cp">{{</span> <span class="nv">article.summary</span> <span class="cp">}}</span><span class="p"></</span><span class="nt">p</span><span class="p">></span>
<span class="p"></</span><span class="nt">div</span><span class="p">></span>
<span class="p"><</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">"meta"</span><span class="p">></span>
<span class="p"><</span><span class="nt">time</span> <span class="na">class</span><span class="o">=</span><span class="s">"published"</span> <span class="na">datetime</span><span class="o">=</span><span class="s">"</span><span class="cp">{{</span> <span class="nv">article.date</span> <span class="o">|</span> <span class="nf">strftime</span><span class="o">(</span><span class="s1">'%Y-%m-%d'</span><span class="o">)</span> <span class="cp">}}</span><span class="s">"</span><span class="p">></span><span class="cp">{{</span> <span class="nv">article.date</span> <span class="o">|</span> <span class="nf">strftime</span><span class="o">(</span><span class="s1">'%b %-d, %Y'</span><span class="o">)</span> <span class="cp">}}</span><span class="p"></</span><span class="nt">time</span><span class="p">></span>
<span class="p"><</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">"#"</span> <span class="na">class</span><span class="o">=</span><span class="s">"author"</span><span class="p">><</span><span class="nt">span</span> <span class="na">class</span><span class="o">=</span><span class="s">"name"</span><span class="p">></span><span class="cp">{{</span> <span class="nv">article.author</span> <span class="cp">}}</span><span class="p"></</span><span class="nt">span</span><span class="p">><</span><span class="nt">img</span> <span class="na">src</span><span class="o">=</span><span class="s">"</span><span class="cp">{{</span> <span class="nv">SITEURL</span> <span class="cp">}}</span><span class="s">/theme/images/avatar.jpg"</span> <span class="na">alt</span><span class="o">=</span><span class="s">""</span> <span class="p">/></</span><span class="nt">a</span><span class="p">></span>
<span class="p"></</span><span class="nt">div</span><span class="p">></span>
<span class="p"></</span><span class="nt">header</span><span class="p">></span>
<span class="hll"> <span class="p"><</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">"single.html"</span> <span class="na">class</span><span class="o">=</span><span class="s">"image featured"</span><span class="p">><</span><span class="nt">img</span> <span class="na">src</span><span class="o">=</span><span class="s">"images/</span><span class="cp">{{</span> <span class="nv">article.image</span> <span class="cp">}}</span><span class="s">"</span> <span class="na">alt</span><span class="o">=</span><span class="s">""</span> <span class="p">/></</span><span class="nt">a</span><span class="p">></span>
</span> <span class="cp">{{</span> <span class="nv">article.content</span> <span class="cp">}}</span>
<span class="p"><</span><span class="nt">footer</span><span class="p">></span>
<span class="p"><</span><span class="nt">ul</span> <span class="na">class</span><span class="o">=</span><span class="s">"actions"</span><span class="p">></span>
<span class="p"><</span><span class="nt">li</span><span class="p">><</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">"single.html"</span> <span class="na">class</span><span class="o">=</span><span class="s">"button large"</span><span class="p">></span>Continue Reading<span class="p"></</span><span class="nt">a</span><span class="p">></</span><span class="nt">li</span><span class="p">></span>
<span class="p"></</span><span class="nt">ul</span><span class="p">></span>
<span class="p"><</span><span class="nt">ul</span> <span class="na">class</span><span class="o">=</span><span class="s">"stats"</span><span class="p">></span>
<span class="cp">{%</span> <span class="k">for</span> <span class="nv">tag</span> <span class="k">in</span> <span class="nv">article.tags</span> <span class="cp">%}</span>
<span class="p"><</span><span class="nt">li</span><span class="p">><</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">"#"</span><span class="p">></span><span class="cp">{{</span> <span class="nv">tag.name</span> <span class="cp">}}</span><span class="p"></</span><span class="nt">a</span><span class="p">></</span><span class="nt">li</span><span class="p">></span>
<span class="cp">{%</span> <span class="k">endfor</span> <span class="cp">%}</span>
<span class="p"></</span><span class="nt">ul</span><span class="p">></span>
<span class="p"></</span><span class="nt">footer</span><span class="p">></span>
<span class="p"></</span><span class="nt">article</span><span class="p">></span>
<span class="cp">{%</span> <span class="k">endfor</span> <span class="cp">%}</span>
</pre></div> </div> </div><p>and in the sidebar</p><div class="code"><div class="title"><code>future-imperfect/templates/index.html</code></div><div class="content"><div class="highlight"><pre> <span class="cm"><!-- Mini Posts --></span>
<span class="p"><</span><span class="nt">section</span><span class="p">></span>
<span class="p"><</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">"mini-posts"</span><span class="p">></span>
<span class="cp">{%</span> <span class="k">for</span> <span class="nv">article</span> <span class="k">in</span> <span class="nv">articles</span><span class="o">[:</span><span class="m">4</span><span class="o">]</span> <span class="cp">%}</span>
<span class="cm"><!-- Mini Post --></span>
<span class="p"><</span><span class="nt">article</span> <span class="na">class</span><span class="o">=</span><span class="s">"mini-post"</span><span class="p">></span>
<span class="p"><</span><span class="nt">header</span><span class="p">></span>
<span class="p"><</span><span class="nt">h3</span><span class="p">><</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">"single.html"</span><span class="p">></span><span class="cp">{{</span> <span class="nv">article.title</span> <span class="cp">}}</span><span class="p"></</span><span class="nt">a</span><span class="p">></</span><span class="nt">h3</span><span class="p">></span>
<span class="p"><</span><span class="nt">time</span> <span class="na">class</span><span class="o">=</span><span class="s">"published"</span> <span class="na">datetime</span><span class="o">=</span><span class="s">"</span><span class="cp">{{</span> <span class="nv">article.date</span> <span class="o">|</span> <span class="nf">strftime</span><span class="o">(</span><span class="s1">'%Y-%m-%d'</span><span class="o">)</span> <span class="cp">}}</span><span class="s">"</span><span class="p">></span><span class="cp">{{</span> <span class="nv">article.date</span> <span class="o">|</span> <span class="nf">strftime</span><span class="o">(</span><span class="s1">'%b %-d, %Y'</span><span class="o">)</span> <span class="cp">}}</span><span class="p"></</span><span class="nt">time</span><span class="p">></span>
<span class="p"><</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">"#"</span> <span class="na">class</span><span class="o">=</span><span class="s">"author"</span><span class="p">><</span><span class="nt">img</span> <span class="na">src</span><span class="o">=</span><span class="s">"</span><span class="cp">{{</span> <span class="nv">SITEURL</span> <span class="cp">}}</span><span class="s">/theme/images/avatar.jpg"</span> <span class="na">alt</span><span class="o">=</span><span class="s">""</span> <span class="p">/></</span><span class="nt">a</span><span class="p">></span>
<span class="p"></</span><span class="nt">header</span><span class="p">></span>
<span class="hll"> <span class="p"><</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">"single.html"</span> <span class="na">class</span><span class="o">=</span><span class="s">"image"</span><span class="p">><</span><span class="nt">img</span> <span class="na">src</span><span class="o">=</span><span class="s">"images/</span><span class="cp">{{</span> <span class="nv">article.image</span> <span class="cp">}}</span><span class="s">"</span> <span class="na">alt</span><span class="o">=</span><span class="s">""</span> <span class="p">/></</span><span class="nt">a</span><span class="p">></span>
</span> <span class="p"></</span><span class="nt">article</span><span class="p">></span>
<span class="cp">{%</span> <span class="k">endfor</span> <span class="cp">%}</span>
<span class="p"></</span><span class="nt">div</span><span class="p">></span>
<span class="p"></</span><span class="nt">section</span><span class="p">></span>
</pre></div> </div> </div><p>Now the page is definitely more appealing!</p><h2 id="advanced-techniques-extend-and-include-3d5d">Advanced techniques: extend and include<a class="headerlink" href="#advanced-techniques-extend-and-include-3d5d" title="Permanent link">¶</a></h2><p>As in everything related to computer programming (and not only) you will soon discover that you are repeating yourself, and one of the top design advice that you should follow says: don't do it.</p><p>Jinja templates provide two tags to help you reduce duplicated code, namely <code>extend</code> and <code>include</code>. To see how they work let's focus our attention on the page of a specific article. When we click on an article we would like to go to a dedicated page, while all links at the moment load the same static page <code>single.html</code>.</p><p>The article page, however, won't be that different from the front page we just created. It might be, as you are free to completely change the style, but in general some elements will be in common, for example the navigation, the sidebar, and the footer.</p><p>In the following section I will show you how to use the Jinja tags <code>extends</code> and <code>include</code> to reuse parts of your theme.</p><h3 id="extends-16a0">Extends</h3><p>Since we want to reuse some parts of the page we need to move them to a "common space". Create a new file called <code>future-imperfect/templates/base.html</code> and move the whole content of <code>index.html</code> into it. Then write this single statement in the now empty <code>index.html</code></p><div class="code"><div class="title"><code>future-imperfect/templates/index.html</code></div><div class="content"><div class="highlight"><pre><span class="cp">{%</span> <span class="k">extends</span> <span class="s2">"base.html"</span> <span class="cp">%}</span>
</pre></div> </div> </div><p>What we did is to tell Jinja that everything we do in <code>index.html</code> should happen on top of <code>base.html</code> (we'll soon discover the meaning of this "on top"). For now you might think about it as <code>index.html</code> copying the content of <code>base.html</code>.</p><p>The problem with this setup is that <code>base.html</code> doesn't have access to the variables that <code>index.html</code> has access to, as <code>base.html</code> is an arbitrary file and not something known to Pelican. Indeed the command <code>pelican -lr</code> that you are running in a terminal should give you this error</p><div class="code"><div class="content"><div class="highlight"><pre>WARNING: Caught exception:
| "'articles_page' is undefined".
</pre></div> </div> </div><p>Since that is something only <code>index.html</code> can provide we need to do something more than just copying the content of <code>base.html</code>, we need to also fill in some parts, which is exactly what you can do with <code>block</code> (see <a href="https://jinja.palletsprojects.com/en/2.11.x/templates/#template-inheritance">Jinja's documentation on template inheritance</a>).</p><p>Grab the whole content of the <code>&lt;div id="main"&gt;</code> and move it in <code>index.html</code> wrapped in <code>{% block content %}</code></p><div class="code"><div class="title"><code>future-imperfect/templates/index.html</code></div><div class="content"><div class="highlight"><pre><span class="cp">{%</span> <span class="k">extends</span> <span class="s2">"base.html"</span> <span class="cp">%}</span>
<span class="cp">{%</span> <span class="k">block</span> <span class="nv">content</span> <span class="cp">%}</span>
<span class="cp">{%</span> <span class="k">for</span> <span class="nv">article</span> <span class="k">in</span> <span class="nv">articles_page.object_list</span> <span class="cp">%}</span>
<span class="cm"><!-- Post --></span>
<span class="p"><</span><span class="nt">article</span> <span class="na">class</span><span class="o">=</span><span class="s">"post"</span><span class="p">></span>
<span class="p"><</span><span class="nt">header</span><span class="p">></span>
<span class="p"><</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">"title"</span><span class="p">></span>
<span class="p"><</span><span class="nt">h2</span><span class="p">><</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">"single.html"</span><span class="p">></span><span class="cp">{{</span> <span class="nv">article.title</span> <span class="cp">}}</span><span class="p"></</span><span class="nt">a</span><span class="p">></</span><span class="nt">h2</span><span class="p">></span>
<span class="p"><</span><span class="nt">p</span><span class="p">></span><span class="cp">{{</span> <span class="nv">article.summary</span> <span class="cp">}}</span><span class="p"></</span><span class="nt">p</span><span class="p">></span>
<span class="p"></</span><span class="nt">div</span><span class="p">></span>
<span class="p"><</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">"meta"</span><span class="p">></span>
<span class="p"><</span><span class="nt">time</span> <span class="na">class</span><span class="o">=</span><span class="s">"published"</span> <span class="na">datetime</span><span class="o">=</span><span class="s">"</span><span class="cp">{{</span> <span class="nv">article.date</span> <span class="o">|</span> <span class="nf">strftime</span><span class="o">(</span><span class="s1">'%Y-%m-%d'</span><span class="o">)</span> <span class="cp">}}</span><span class="s">"</span><span class="p">></span><span class="cp">{{</span> <span class="nv">article.date</span> <span class="o">|</span> <span class="nf">strftime</span><span class="o">(</span><span class="s1">'%b %-d, %Y'</span><span class="o">)</span> <span class="cp">}}</span><span class="p"></</span><span class="nt">time</span><span class="p">></span>
<span class="p"><</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">"#"</span> <span class="na">class</span><span class="o">=</span><span class="s">"author"</span><span class="p">><</span><span class="nt">span</span> <span class="na">class</span><span class="o">=</span><span class="s">"name"</span><span class="p">></span><span class="cp">{{</span> <span class="nv">article.author</span> <span class="cp">}}</span><span class="p"></</span><span class="nt">span</span><span class="p">><</span><span class="nt">img</span> <span class="na">src</span><span class="o">=</span><span class="s">"</span><span class="cp">{{</span> <span class="nv">SITEURL</span> <span class="cp">}}</span><span class="s">/theme/images/avatar.jpg"</span> <span class="na">alt</span><span class="o">=</span><span class="s">""</span> <span class="p">/></</span><span class="nt">a</span><span class="p">></span>
<span class="p"></</span><span class="nt">div</span><span class="p">></span>
<span class="p"></</span><span class="nt">header</span><span class="p">></span>
<span class="p"><</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">"single.html"</span> <span class="na">class</span><span class="o">=</span><span class="s">"image featured"</span><span class="p">><</span><span class="nt">img</span> <span class="na">src</span><span class="o">=</span><span class="s">"images/</span><span class="cp">{{</span> <span class="nv">article.image</span> <span class="cp">}}</span><span class="s">"</span> <span class="na">alt</span><span class="o">=</span><span class="s">""</span> <span class="p">/></</span><span class="nt">a</span><span class="p">></span>
<span class="cp">{{</span> <span class="nv">article.content</span> <span class="cp">}}</span>
<span class="p"><</span><span class="nt">footer</span><span class="p">></span>
<span class="p"><</span><span class="nt">ul</span> <span class="na">class</span><span class="o">=</span><span class="s">"actions"</span><span class="p">></span>
<span class="p"><</span><span class="nt">li</span><span class="p">><</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">"single.html"</span> <span class="na">class</span><span class="o">=</span><span class="s">"button large"</span><span class="p">></span>Continue Reading<span class="p"></</span><span class="nt">a</span><span class="p">></</span><span class="nt">li</span><span class="p">></span>
<span class="p"></</span><span class="nt">ul</span><span class="p">></span>
<span class="p"><</span><span class="nt">ul</span> <span class="na">class</span><span class="o">=</span><span class="s">"stats"</span><span class="p">></span>
<span class="cp">{%</span> <span class="k">for</span> <span class="nv">tag</span> <span class="k">in</span> <span class="nv">article.tags</span> <span class="cp">%}</span>
<span class="p"><</span><span class="nt">li</span><span class="p">><</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">"#"</span><span class="p">></span><span class="cp">{{</span> <span class="nv">tag.name</span> <span class="cp">}}</span><span class="p"></</span><span class="nt">a</span><span class="p">></</span><span class="nt">li</span><span class="p">></span>
<span class="cp">{%</span> <span class="k">endfor</span> <span class="cp">%}</span>
<span class="p"></</span><span class="nt">ul</span><span class="p">></span>
<span class="p"></</span><span class="nt">footer</span><span class="p">></span>
<span class="p"></</span><span class="nt">article</span><span class="p">></span>
<span class="cp">{%</span> <span class="k">endfor</span> <span class="cp">%}</span>
<span class="cm"><!-- Pagination --></span>
<span class="p"><</span><span class="nt">ul</span> <span class="na">class</span><span class="o">=</span><span class="s">"actions pagination"</span><span class="p">></span>
<span class="cp">{%</span> <span class="k">if</span> <span class="nv">articles_page.has_previous</span><span class="o">()</span> <span class="cp">%}</span>
<span class="p"><</span><span class="nt">li</span><span class="p">><</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">"/</span><span class="cp">{{</span> <span class="nv">articles_previous_page.url</span> <span class="cp">}}</span><span class="s">"</span> <span class="na">class</span><span class="o">=</span><span class="s">"button large previous"</span><span class="p">></span>Previous Page<span class="p"></</span><span class="nt">a</span><span class="p">></</span><span class="nt">li</span><span class="p">></span>
<span class="cp">{%</span> <span class="k">else</span> <span class="cp">%}</span>
<span class="p"><</span><span class="nt">li</span><span class="p">><</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">""</span> <span class="na">class</span><span class="o">=</span><span class="s">"disabled button large previous"</span><span class="p">></span>Previous Page<span class="p"></</span><span class="nt">a</span><span class="p">></</span><span class="nt">li</span><span class="p">></span>
<span class="cp">{%</span> <span class="k">endif</span> <span class="cp">%}</span>
<span class="cp">{%</span> <span class="k">if</span> <span class="nv">articles_page.has_next</span><span class="o">()</span> <span class="cp">%}</span>
<span class="p"><</span><span class="nt">li</span><span class="p">><</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">"/</span><span class="cp">{{</span> <span class="nv">articles_next_page.url</span> <span class="cp">}}</span><span class="s">"</span> <span class="na">class</span><span class="o">=</span><span class="s">"button large next"</span><span class="p">></span>Next Page<span class="p"></</span><span class="nt">a</span><span class="p">></</span><span class="nt">li</span><span class="p">></span>
<span class="cp">{%</span> <span class="k">else</span> <span class="cp">%}</span>
<span class="p"><</span><span class="nt">li</span><span class="p">><</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">"#"</span> <span class="na">class</span><span class="o">=</span><span class="s">"disabled button large next"</span><span class="p">></span>Next Page<span class="p"></</span><span class="nt">a</span><span class="p">></</span><span class="nt">li</span><span class="p">></span>
<span class="cp">{%</span> <span class="k">endif</span> <span class="cp">%}</span>
<span class="p"></</span><span class="nt">ul</span><span class="p">></span>
<span class="cp">{%</span> <span class="k">endblock</span> <span class="cp">%}</span>
</pre></div> </div> </div><p>At the same time fill the empty space you left in <code>base.html</code> with a call for that block</p><div class="code"><div class="title"><code>future-imperfect/templates/base.html</code></div><div class="content"><div class="highlight"><pre> <span class="cm"><!-- Main --></span>
<span class="p"><</span><span class="nt">div</span> <span class="na">id</span><span class="o">=</span><span class="s">"main"</span><span class="p">></span>
<span class="hll"> <span class="cp">{%</span> <span class="k">block</span> <span class="nv">content</span> <span class="cp">%}{%</span> <span class="k">endblock</span> <span class="cp">%}</span>
</span> <span class="p"></</span><span class="nt">div</span><span class="p">></span>
</pre></div> </div> </div><p>When this is done, reload the page and... nothing should have changed. Sorry, but this is one of those things that happen behind the scenes and that do not have any immediate benefit. However, Pelican shouldn't give you any error on the command line, which is comforting.</p><p>To see the benefit of what we did let's move on and create the page for the single article, <code>article.html</code></p><div class="code"><div class="title"><code>future-imperfect/templates/article.html</code></div><div class="content"><div class="highlight"><pre><span class="cp">{%</span> <span class="k">extends</span> <span class="s2">"base.html"</span> <span class="cp">%}</span>
</pre></div> </div> </div><p>As we said before <code>base.html</code> is supposed to be the common part of all pages, so <code>article.html</code> should start from that as well. To check how that page looks like now let's update the links from the articles in the main body. Open <code>index.html</code> and replace the URLs of each article</p><div class="code"><div class="title"><code>future-imperfect/templates/index.html</code></div><div class="content"><div class="highlight"><pre><span class="p"><</span><span class="nt">article</span> <span class="na">class</span><span class="o">=</span><span class="s">"post"</span><span class="p">></span>
<span class="p"><</span><span class="nt">header</span><span class="p">></span>
<span class="p"><</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">"title"</span><span class="p">></span>
<span class="hll"> <span class="p"><</span><span class="nt">h2</span><span class="p">><</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">"</span><span class="cp">{{</span> <span class="nv">article.url</span> <span class="cp">}}</span><span class="s">"</span><span class="p">></span><span class="cp">{{</span> <span class="nv">article.title</span> <span class="cp">}}</span><span class="p"></</span><span class="nt">a</span><span class="p">></</span><span class="nt">h2</span><span class="p">></span>
</span> <span class="p"><</span><span class="nt">p</span><span class="p">></span><span class="cp">{{</span> <span class="nv">article.summary</span> <span class="cp">}}</span><span class="p"></</span><span class="nt">p</span><span class="p">></span>
<span class="p"></</span><span class="nt">div</span><span class="p">></span>
<span class="p"><</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">"meta"</span><span class="p">></span>
<span class="p"><</span><span class="nt">time</span> <span class="na">class</span><span class="o">=</span><span class="s">"published"</span> <span class="na">datetime</span><span class="o">=</span><span class="s">"</span><span class="cp">{{</span> <span class="nv">article.date</span> <span class="o">|</span> <span class="nf">strftime</span><span class="o">(</span><span class="s1">'%Y-%m-%d'</span><span class="o">)</span> <span class="cp">}}</span><span class="s">"</span><span class="p">></span><span class="cp">{{</span> <span class="nv">article.date</span> <span class="o">|</span> <span class="nf">strftime</span><span class="o">(</span><span class="s1">'%b %-d, %Y'</span><span class="o">)</span> <span class="cp">}}</span><span class="p"></</span><span class="nt">time</span><span class="p">></span>
<span class="p"><</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">"#"</span> <span class="na">class</span><span class="o">=</span><span class="s">"author"</span><span class="p">><</span><span class="nt">span</span> <span class="na">class</span><span class="o">=</span><span class="s">"name"</span><span class="p">></span><span class="cp">{{</span> <span class="nv">article.author</span> <span class="cp">}}</span><span class="p"></</span><span class="nt">span</span><span class="p">><</span><span class="nt">img</span> <span class="na">src</span><span class="o">=</span><span class="s">"</span><span class="cp">{{</span> <span class="nv">SITEURL</span> <span class="cp">}}</span><span class="s">/theme/images/avatar.jpg"</span> <span class="na">alt</span><span class="o">=</span><span class="s">""</span> <span class="p">/></</span><span class="nt">a</span><span class="p">></span>
<span class="p"></</span><span class="nt">div</span><span class="p">></span>
<span class="p"></</span><span class="nt">header</span><span class="p">></span>
<span class="hll"> <span class="p"><</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">"</span><span class="cp">{{</span> <span class="nv">article.url</span> <span class="cp">}}</span><span class="s">"</span> <span class="na">class</span><span class="o">=</span><span class="s">"image featured"</span><span class="p">><</span><span class="nt">img</span> <span class="na">src</span><span class="o">=</span><span class="s">"images/</span><span class="cp">{{</span> <span class="nv">article.image</span> <span class="cp">}}</span><span class="s">"</span> <span class="na">alt</span><span class="o">=</span><span class="s">""</span> <span class="p">/></</span><span class="nt">a</span><span class="p">></span>
</span> <span class="cp">{{</span> <span class="nv">article.content</span> <span class="cp">}}</span>
<span class="p"><</span><span class="nt">footer</span><span class="p">></span>
<span class="p"><</span><span class="nt">ul</span> <span class="na">class</span><span class="o">=</span><span class="s">"actions"</span><span class="p">></span>
<span class="hll"> <span class="p"><</span><span class="nt">li</span><span class="p">><</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">"</span><span class="cp">{{</span> <span class="nv">article.url</span> <span class="cp">}}</span><span class="s">"</span> <span class="na">class</span><span class="o">=</span><span class="s">"button large"</span><span class="p">></span>Continue Reading<span class="p"></</span><span class="nt">a</span><span class="p">></</span><span class="nt">li</span><span class="p">></span>
</span> <span class="p"></</span><span class="nt">ul</span><span class="p">></span>
<span class="p"><</span><span class="nt">ul</span> <span class="na">class</span><span class="o">=</span><span class="s">"stats"</span><span class="p">></span>
<span class="cp">{%</span> <span class="k">for</span> <span class="nv">tag</span> <span class="k">in</span> <span class="nv">article.tags</span> <span class="cp">%}</span>
<span class="p"><</span><span class="nt">li</span><span class="p">><</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">"#"</span><span class="p">></span><span class="cp">{{</span> <span class="nv">tag.name</span> <span class="cp">}}</span><span class="p"></</span><span class="nt">a</span><span class="p">></</span><span class="nt">li</span><span class="p">></span>
<span class="cp">{%</span> <span class="k">endfor</span> <span class="cp">%}</span>
<span class="p"></</span><span class="nt">ul</span><span class="p">></span>
<span class="p"></</span><span class="nt">footer</span><span class="p">></span>
<span class="p"></</span><span class="nt">article</span><span class="p">></span>
</pre></div> </div> </div><p>Now if you render the front page and click on the title of a post in the main column you will end up in the page dedicated to it, which has a worrying empty central column! Well, after all <code>article.html</code> extends <code>base.html</code> but doesn't provide anything for the block <code>content</code>, so let's fix this</p><div class="code"><div class="title"><code>future-imperfect/templates/article.html</code></div><div class="content"><div class="highlight"><pre><span class="cp">{%</span> <span class="k">extends</span> <span class="s2">"base.html"</span> <span class="cp">%}</span>
<span class="cp">{%</span> <span class="k">block</span> <span class="nv">content</span> <span class="cp">%}</span>
<span class="cm"><!-- Post --></span>
<span class="p"><</span><span class="nt">article</span> <span class="na">class</span><span class="o">=</span><span class="s">"post"</span><span class="p">></span>
<span class="p"><</span><span class="nt">header</span><span class="p">></span>
<span class="p"><</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">"title"</span><span class="p">></span>
<span class="p"><</span><span class="nt">h2</span><span class="p">><</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">"</span><span class="cp">{{</span> <span class="nv">article.url</span> <span class="cp">}}</span><span class="s">"</span><span class="p">></span><span class="cp">{{</span> <span class="nv">article.title</span> <span class="cp">}}</span><span class="p"></</span><span class="nt">a</span><span class="p">></</span><span class="nt">h2</span><span class="p">></span>
<span class="p"><</span><span class="nt">p</span><span class="p">></span><span class="cp">{{</span> <span class="nv">article.summary</span> <span class="cp">}}</span><span class="p"></</span><span class="nt">p</span><span class="p">></span>
<span class="p"></</span><span class="nt">div</span><span class="p">></span>
<span class="p"><</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">"meta"</span><span class="p">></span>
<span class="p"><</span><span class="nt">time</span> <span class="na">class</span><span class="o">=</span><span class="s">"published"</span> <span class="na">datetime</span><span class="o">=</span><span class="s">"</span><span class="cp">{{</span> <span class="nv">article.date</span> <span class="o">|</span> <span class="nf">strftime</span><span class="o">(</span><span class="s1">'%Y-%m-%d'</span><span class="o">)</span> <span class="cp">}}</span><span class="s">"</span><span class="p">></span><span class="cp">{{</span> <span class="nv">article.date</span> <span class="o">|</span> <span class="nf">strftime</span><span class="o">(</span><span class="s1">'%b %-d, %Y'</span><span class="o">)</span> <span class="cp">}}</span><span class="p"></</span><span class="nt">time</span><span class="p">></span>
<span class="p"><</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">"#"</span> <span class="na">class</span><span class="o">=</span><span class="s">"author"</span><span class="p">><</span><span class="nt">span</span> <span class="na">class</span><span class="o">=</span><span class="s">"name"</span><span class="p">></span><span class="cp">{{</span> <span class="nv">article.author</span> <span class="cp">}}</span><span class="p"></</span><span class="nt">span</span><span class="p">><</span><span class="nt">img</span> <span class="na">src</span><span class="o">=</span><span class="s">"</span><span class="cp">{{</span> <span class="nv">SITEURL</span> <span class="cp">}}</span><span class="s">/theme/images/avatar.jpg"</span> <span class="na">alt</span><span class="o">=</span><span class="s">""</span> <span class="p">/></</span><span class="nt">a</span><span class="p">></span>
<span class="p"></</span><span class="nt">div</span><span class="p">></span>
<span class="p"></</span><span class="nt">header</span><span class="p">></span>
<span class="p"><</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">"</span><span class="cp">{{</span> <span class="nv">article.url</span> <span class="cp">}}</span><span class="s">"</span> <span class="na">class</span><span class="o">=</span><span class="s">"image featured"</span><span class="p">><</span><span class="nt">img</span> <span class="na">src</span><span class="o">=</span><span class="s">"images/</span><span class="cp">{{</span> <span class="nv">article.image</span> <span class="cp">}}</span><span class="s">"</span> <span class="na">alt</span><span class="o">=</span><span class="s">""</span> <span class="p">/></</span><span class="nt">a</span><span class="p">></span>
<span class="cp">{{</span> <span class="nv">article.content</span> <span class="cp">}}</span>
<span class="p"><</span><span class="nt">footer</span><span class="p">></span>
<span class="p"><</span><span class="nt">ul</span> <span class="na">class</span><span class="o">=</span><span class="s">"actions"</span><span class="p">></span>
<span class="p"><</span><span class="nt">li</span><span class="p">><</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">"</span><span class="cp">{{</span> <span class="nv">article.url</span> <span class="cp">}}</span><span class="s">"</span> <span class="na">class</span><span class="o">=</span><span class="s">"button large"</span><span class="p">></span>Continue Reading<span class="p"></</span><span class="nt">a</span><span class="p">></</span><span class="nt">li</span><span class="p">></span>
<span class="p"></</span><span class="nt">ul</span><span class="p">></span>
<span class="p"><</span><span class="nt">ul</span> <span class="na">class</span><span class="o">=</span><span class="s">"stats"</span><span class="p">></span>
<span class="cp">{%</span> <span class="k">for</span> <span class="nv">tag</span> <span class="k">in</span> <span class="nv">article.tags</span> <span class="cp">%}</span>
<span class="p"><</span><span class="nt">li</span><span class="p">><</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">"#"</span><span class="p">></span><span class="cp">{{</span> <span class="nv">tag.name</span> <span class="cp">}}</span><span class="p"></</span><span class="nt">a</span><span class="p">></</span><span class="nt">li</span><span class="p">></span>
<span class="cp">{%</span> <span class="k">endfor</span> <span class="cp">%}</span>
<span class="p"></</span><span class="nt">ul</span><span class="p">></span>
<span class="p"></</span><span class="nt">footer</span><span class="p">></span>
<span class="p"></</span><span class="nt">article</span><span class="p">></span>
<span class="cp">{%</span> <span class="k">endblock</span> <span class="cp">%}</span>
</pre></div> </div> </div><p>I copied the content of the block from the loop in <code>index.html</code>. In this simple example they have the same code, but in a real production environment you might want to differentiate them. As you can see <code>article.html</code> provides the variable <code>article</code> out of the box. Please note that the page of each article doesn't show the pagination buttons, as they are not part of <code>article.html</code>.</p><h3 id="include-fe56">Include</h3><p>When you write a theme there are often snippets of code that you might need to repeat in different parts of the whole site. The sidebar is typically a good example of a collection of such snippets, like the "About" section or the list of latest posts that you might want to reuse somewhere else.</p><p>Jinja provides the tag <code>include</code> that allows you to easily inject the content of another template file into the current one. Let's see how it works moving the list of latest posts to a separate file.</p><p>Move the content of the mini posts section from <code>base.html</code> to a file called <code>templates/includes/latest_posts.html</code></p><div class="code"><div class="title"><code>templates/includes/latest_posts.html</code></div><div class="content"><div class="highlight"><pre><span class="cm"><!-- Mini Posts --></span>
<span class="p"><</span><span class="nt">section</span><span class="p">></span>
<span class="p"><</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">"mini-posts"</span><span class="p">></span>
<span class="cp">{%</span> <span class="k">for</span> <span class="nv">article</span> <span class="k">in</span> <span class="nv">articles</span><span class="o">[:</span><span class="m">4</span><span class="o">]</span> <span class="cp">%}</span>
<span class="cm"><!-- Mini Post --></span>
<span class="p"><</span><span class="nt">article</span> <span class="na">class</span><span class="o">=</span><span class="s">"mini-post"</span><span class="p">></span>
<span class="p"><</span><span class="nt">header</span><span class="p">></span>
<span class="p"><</span><span class="nt">h3</span><span class="p">><</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">"single.html"</span><span class="p">></span><span class="cp">{{</span> <span class="nv">article.title</span> <span class="cp">}}</span><span class="p"></</span><span class="nt">a</span><span class="p">></</span><span class="nt">h3</span><span class="p">></span>
<span class="p"><</span><span class="nt">time</span> <span class="na">class</span><span class="o">=</span><span class="s">"published"</span> <span class="na">datetime</span><span class="o">=</span><span class="s">"</span><span class="cp">{{</span> <span class="nv">article.date</span> <span class="o">|</span> <span class="nf">strftime</span><span class="o">(</span><span class="s1">'%Y-%m-%d'</span><span class="o">)</span> <span class="cp">}}</span><span class="s">"</span><span class="p">></span><span class="cp">{{</span> <span class="nv">article.date</span> <span class="o">|</span> <span class="nf">strftime</span><span class="o">(</span><span class="s1">'%b %-d, %Y'</span><span class="o">)</span> <span class="cp">}}</span><span class="p"></</span><span class="nt">time</span><span class="p">></span>
<span class="p"><</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">"#"</span> <span class="na">class</span><span class="o">=</span><span class="s">"author"</span><span class="p">><</span><span class="nt">img</span> <span class="na">src</span><span class="o">=</span><span class="s">"</span><span class="cp">{{</span> <span class="nv">SITEURL</span> <span class="cp">}}</span><span class="s">/theme/images/avatar.jpg"</span> <span class="na">alt</span><span class="o">=</span><span class="s">""</span> <span class="p">/></</span><span class="nt">a</span><span class="p">></span>
<span class="p"></</span><span class="nt">header</span><span class="p">></span>
<span class="p"><</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">"single.html"</span> <span class="na">class</span><span class="o">=</span><span class="s">"image"</span><span class="p">><</span><span class="nt">img</span> <span class="na">src</span><span class="o">=</span><span class="s">"images/</span><span class="cp">{{</span> <span class="nv">article.image</span> <span class="cp">}}</span><span class="s">"</span> <span class="na">alt</span><span class="o">=</span><span class="s">""</span> <span class="p">/></</span><span class="nt">a</span><span class="p">></span>
<span class="p"></</span><span class="nt">article</span><span class="p">></span>
<span class="cp">{%</span> <span class="k">endfor</span> <span class="cp">%}</span>
<span class="p"></</span><span class="nt">div</span><span class="p">></span>
<span class="p"></</span><span class="nt">section</span><span class="p">></span>
</pre></div> </div> </div><p>And replace it with a call to <code>include</code> in <code>base.html</code></p><div class="code"><div class="title"><code>templates/includes/base.html</code></div><div class="content"><div class="highlight"><pre> <span class="cm"><!-- Intro --></span>
<span class="p"><</span><span class="nt">section</span> <span class="na">id</span><span class="o">=</span><span class="s">"intro"</span><span class="p">></span>
<span class="p"><</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">"#"</span> <span class="na">class</span><span class="o">=</span><span class="s">"logo"</span><span class="p">><</span><span class="nt">img</span> <span class="na">src</span><span class="o">=</span><span class="s">"</span><span class="cp">{{</span> <span class="nv">SITEURL</span> <span class="cp">}}</span><span class="s">/theme/images/logo.jpg"</span> <span class="na">alt</span><span class="o">=</span><span class="s">""</span> <span class="p">/></</span><span class="nt">a</span><span class="p">></span>
<span class="p"><</span><span class="nt">header</span><span class="p">></span>
<span class="p"><</span><span class="nt">h2</span><span class="p">></span><span class="cp">{{</span> <span class="nv">SITENAME</span> <span class="cp">}}</span><span class="p"></</span><span class="nt">h2</span><span class="p">></span>
<span class="p"><</span><span class="nt">p</span><span class="p">></span><span class="cp">{{</span> <span class="nv">SITESUBTITLE</span> <span class="cp">}}</span><span class="p"></</span><span class="nt">p</span><span class="p">></span>
<span class="p"></</span><span class="nt">header</span><span class="p">></span>
<span class="p"></</span><span class="nt">section</span><span class="p">></span>
<span class="hll"> <span class="cp">{%</span> <span class="k">include</span> <span class="s1">'includes/latest_posts.html'</span> <span class="cp">%}</span>
</span>
<span class="cm"><!-- About --></span>
<span class="p"><</span><span class="nt">section</span> <span class="na">class</span><span class="o">=</span><span class="s">"blurb"</span><span class="p">></span>
<span class="p"><</span><span class="nt">h2</span><span class="p">></span>About<span class="p"></</span><span class="nt">h2</span><span class="p">></span>
<span class="p"><</span><span class="nt">p</span><span class="p">></span>Mauris neque quam, fermentum ut nisl vitae, convallis maximus nisl. Sed mattis nunc id lorem euismod amet placerat. Vivamus porttitor magna enim, ac accumsan tortor cursus at phasellus sed ultricies.<span class="p"></</span><span class="nt">p</span><span class="p">></span>
<span class="p"><</span><span class="nt">ul</span> <span class="na">class</span><span class="o">=</span><span class="s">"actions"</span><span class="p">></span>
<span class="p"><</span><span class="nt">li</span><span class="p">><</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">"#"</span> <span class="na">class</span><span class="o">=</span><span class="s">"button"</span><span class="p">></span>Learn More<span class="p"></</span><span class="nt">a</span><span class="p">></</span><span class="nt">li</span><span class="p">></span>
<span class="p"></</span><span class="nt">ul</span><span class="p">></span>
<span class="p"></</span><span class="nt">section</span><span class="p">></span>
</pre></div> </div> </div><p>Again, reloading the page won't show anything different, but now we isolated a piece of code that shows the latest posts and we can reuse it in another part of the site which is not the sidebar. You can find the documentation of <code>include</code> at <a href="https://jinja.palletsprojects.com/en/2.11.x/templates/#include">https://jinja.palletsprojects.com/en/2.11.x/templates/#include</a>.</p><h3 id="deep-dive-e364">Deep dive</h3><p>What is the difference between <code>extends</code> and <code>include</code>? Which one shall you use?</p><p>The difference between extending and including is the same difference that lies between a <em>framework</em> and a <em>library</em> in the context of programming languages. A framework provides the bulk of the system, and we provide the code for specific operations, while a library provides specific code that we need to put in a bigger picture. This about a Web framework like Django or Flask: they already "work" in the background, but until you provide the endpoints they don't do anything specific. At the same time, when you need to encrypt a password you import a library and use its functions.</p><p>In the same way <code>extends</code> means that another template is providing the main part of the page and that we provide the content of the blocks. When we use <code>include</code> the opposite happens, we get a specific snippet of code and insert it in some wider context.</p><p>As there are no limitations to the number of lines contained in a block or in an imported snippet, there is a certain amount of overlap between the two. Sometimes it might not be immediately clear which one to use, but in the vast majority of cases it should be straightforward.</p><h2 id="preview-articles-5d7d">Preview articles<a class="headerlink" href="#preview-articles-5d7d" title="Permanent link">¶</a></h2><p>Earlier in the post I mentioned a way to create the preview of articles, so now that we have two different pages it makes sense to implement that.</p><p>As I said before the preview of an article has to be created before the content is converted into HTML, or we might leave open tags. Pelican supports this mechanism out of the box, through the <code>summary</code> metadata. If you specify a summary (as I did through the random generation script), Pelican won't do anything, but id the summary is not present it will be initialised with a preview of the article.</p><p>The two variables involved in this process are <code>SUMMARY_MAX_LENGTH</code> and <code>SUMMARY_END_SUFFIX</code> (see <a href="https://docs.getpelican.com/en/latest/settings.html">the documentation</a>), but we can accept the default values for our little project.</p><p>To see the summary in action let's open the last post (<code>post20.markdown</code>) and remove the line <code>Summary: Summary of post 20</code>. Then we need to adjust the code of the page to properly display the summary as content.</p><div class="code"><div class="title"><code>templates/includes/index.html</code></div><div class="content"><div class="highlight"><pre><span class="cp">{%</span> <span class="k">for</span> <span class="nv">article</span> <span class="k">in</span> <span class="nv">articles_page.object_list</span> <span class="cp">%}</span>
<span class="cm"><!-- Post --></span>
<span class="p"><</span><span class="nt">article</span> <span class="na">class</span><span class="o">=</span><span class="s">"post"</span><span class="p">></span>
<span class="p"><</span><span class="nt">header</span><span class="p">></span>
<span class="p"><</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">"title"</span><span class="p">></span>
<span class="p"><</span><span class="nt">h2</span><span class="p">><</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">"</span><span class="cp">{{</span> <span class="nv">article.url</span> <span class="cp">}}</span><span class="s">"</span><span class="p">></span><span class="cp">{{</span> <span class="nv">article.title</span> <span class="cp">}}</span><span class="p"></</span><span class="nt">a</span><span class="p">></</span><span class="nt">h2</span><span class="p">></span>
<span class="hll">
</span> <span class="p"></</span><span class="nt">div</span><span class="p">></span>
<span class="p"><</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">"meta"</span><span class="p">></span>
<span class="p"><</span><span class="nt">time</span> <span class="na">class</span><span class="o">=</span><span class="s">"published"</span> <span class="na">datetime</span><span class="o">=</span><span class="s">"</span><span class="cp">{{</span> <span class="nv">article.date</span> <span class="o">|</span> <span class="nf">strftime</span><span class="o">(</span><span class="s1">'%Y-%m-%d'</span><span class="o">)</span> <span class="cp">}}</span><span class="s">"</span><span class="p">></span><span class="cp">{{</span> <span class="nv">article.date</span> <span class="o">|</span> <span class="nf">strftime</span><span class="o">(</span><span class="s1">'%b %-d, %Y'</span><span class="o">)</span> <span class="cp">}}</span><span class="p"></</span><span class="nt">time</span><span class="p">></span>
<span class="p"><</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">"#"</span> <span class="na">class</span><span class="o">=</span><span class="s">"author"</span><span class="p">><</span><span class="nt">span</span> <span class="na">class</span><span class="o">=</span><span class="s">"name"</span><span class="p">></span><span class="cp">{{</span> <span class="nv">article.author</span> <span class="cp">}}</span><span class="p"></</span><span class="nt">span</span><span class="p">><</span><span class="nt">img</span> <span class="na">src</span><span class="o">=</span><span class="s">"</span><span class="cp">{{</span> <span class="nv">SITEURL</span><span class="cp">}}</span><span class="s">/theme/images/avatar.jpg"</span> <span class="na">alt</span><span class="o">=</span><span class="s">""</span> <span class="p">/></</span><span class="nt">a</span><span class="p">></span>
<span class="p"></</span><span class="nt">div</span><span class="p">></span>
<span class="p"></</span><span class="nt">header</span><span class="p">></span>
<span class="p"><</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">"</span><span class="cp">{{</span> <span class="nv">article.url</span> <span class="cp">}}</span><span class="s">"</span> <span class="na">class</span><span class="o">=</span><span class="s">"image featured"</span><span class="p">><</span><span class="nt">img</span> <span class="na">src</span><span class="o">=</span><span class="s">"images/</span><span class="cp">{{</span> <span class="nv">article.image</span> <span class="cp">}}</span><span class="s">"</span> <span class="na">alt</span><span class="o">=</span><span class="s">""</span> <span class="p">/></</span><span class="nt">a</span><span class="p">></span>
<span class="hll"> <span class="cp">{{</span> <span class="nv">article.summary</span> <span class="cp">}}</span>
</span> <span class="p"><</span><span class="nt">footer</span><span class="p">></span>
<span class="p"><</span><span class="nt">ul</span> <span class="na">class</span><span class="o">=</span><span class="s">"actions"</span><span class="p">></span>
<span class="p"><</span><span class="nt">li</span><span class="p">><</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">"</span><span class="cp">{{</span> <span class="nv">article.url</span> <span class="cp">}}</span><span class="s">"</span> <span class="na">class</span><span class="o">=</span><span class="s">"button large"</span><span class="p">></span>Continue Reading<span class="p"></</span><span class="nt">a</span><span class="p">></</span><span class="nt">li</span><span class="p">></span>
<span class="p"></</span><span class="nt">ul</span><span class="p">></span>
<span class="p"><</span><span class="nt">ul</span> <span class="na">class</span><span class="o">=</span><span class="s">"stats"</span><span class="p">></span>
<span class="cp">{%</span> <span class="k">for</span> <span class="nv">tag</span> <span class="k">in</span> <span class="nv">article.tags</span> <span class="cp">%}</span>
<span class="p"><</span><span class="nt">li</span><span class="p">><</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">"#"</span><span class="p">></span><span class="cp">{{</span> <span class="nv">tag.name</span> <span class="cp">}}</span><span class="p"></</span><span class="nt">a</span><span class="p">></</span><span class="nt">li</span><span class="p">></span>
<span class="cp">{%</span> <span class="k">endfor</span> <span class="cp">%}</span>
<span class="p"></</span><span class="nt">ul</span><span class="p">></span>
<span class="p"></</span><span class="nt">footer</span><span class="p">></span>
<span class="p"></</span><span class="nt">article</span><span class="p">></span>
<span class="cp">{%</span> <span class="k">endfor</span> <span class="cp">%}</span>
</pre></div> </div> </div><p>In the article page, instead we want the content to be displayed, so we just need to remove the summary (which at this point is not a single line that can be easily displayed under the title.</p><div class="code"><div class="title"><code>templates/includes/article.html</code></div><div class="content"><div class="highlight"><pre><span class="cp">{%</span> <span class="k">block</span> <span class="nv">content</span> <span class="cp">%}</span>
<span class="cm"><!-- Post --></span>
<span class="p"><</span><span class="nt">article</span> <span class="na">class</span><span class="o">=</span><span class="s">"post"</span><span class="p">></span>
<span class="p"><</span><span class="nt">header</span><span class="p">></span>
<span class="p"><</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">"title"</span><span class="p">></span>
<span class="p"><</span><span class="nt">h2</span><span class="p">><</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">"</span><span class="cp">{{</span> <span class="nv">article.url</span> <span class="cp">}}</span><span class="s">"</span><span class="p">></span><span class="cp">{{</span> <span class="nv">article.title</span> <span class="cp">}}</span><span class="p"></</span><span class="nt">a</span><span class="p">></</span><span class="nt">h2</span><span class="p">></span>
<span class="hll">
</span> <span class="p"></</span><span class="nt">div</span><span class="p">></span>
<span class="p"><</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">"meta"</span><span class="p">></span>
<span class="p"><</span><span class="nt">time</span> <span class="na">class</span><span class="o">=</span><span class="s">"published"</span> <span class="na">datetime</span><span class="o">=</span><span class="s">"</span><span class="cp">{{</span> <span class="nv">article.date</span> <span class="o">|</span> <span class="nf">strftime</span><span class="o">(</span><span class="s1">'%Y-%m-%d'</span><span class="o">)</span> <span class="cp">}}</span><span class="s">"</span><span class="p">></span><span class="cp">{{</span> <span class="nv">article.date</span> <span class="o">|</span> <span class="nf">strftime</span><span class="o">(</span><span class="s1">'%b %-d, %Y'</span><span class="o">)</span> <span class="cp">}}</span><span class="p"></</span><span class="nt">time</span><span class="p">></span>
<span class="p"><</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">"#"</span> <span class="na">class</span><span class="o">=</span><span class="s">"author"</span><span class="p">><</span><span class="nt">span</span> <span class="na">class</span><span class="o">=</span><span class="s">"name"</span><span class="p">></span><span class="cp">{{</span> <span class="nv">article.author</span> <span class="cp">}}</span><span class="p"></</span><span class="nt">span</span><span class="p">><</span><span class="nt">img</span> <span class="na">src</span><span class="o">=</span><span class="s">"</span><span class="cp">{{</span> <span class="nv">SITEURL</span> <span class="cp">}}</span><span class="s">/theme/images/avatar.jpg"</span> <span class="na">alt</span><span class="o">=</span><span class="s">""</span> <span class="p">/></</span><span class="nt">a</span><span class="p">></span>
<span class="p"></</span><span class="nt">div</span><span class="p">></span>
<span class="p"></</span><span class="nt">header</span><span class="p">></span>
<span class="p"><</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">"</span><span class="cp">{{</span> <span class="nv">article.url</span> <span class="cp">}}</span><span class="s">"</span> <span class="na">class</span><span class="o">=</span><span class="s">"image featured"</span><span class="p">><</span><span class="nt">img</span> <span class="na">src</span><span class="o">=</span><span class="s">"images/</span><span class="cp">{{</span> <span class="nv">article.image</span> <span class="cp">}}</span><span class="s">"</span> <span class="na">alt</span><span class="o">=</span><span class="s">""</span> <span class="p">/></</span><span class="nt">a</span><span class="p">></span>
<span class="cp">{{</span> <span class="nv">article.content</span> <span class="cp">}}</span>
<span class="p"><</span><span class="nt">footer</span><span class="p">></span>
<span class="p"><</span><span class="nt">ul</span> <span class="na">class</span><span class="o">=</span><span class="s">"actions"</span><span class="p">></span>
<span class="p"><</span><span class="nt">li</span><span class="p">><</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">"</span><span class="cp">{{</span> <span class="nv">article.url</span> <span class="cp">}}</span><span class="s">"</span> <span class="na">class</span><span class="o">=</span><span class="s">"button large"</span><span class="p">></span>Continue Reading<span class="p"></</span><span class="nt">a</span><span class="p">></</span><span class="nt">li</span><span class="p">></span>
<span class="p"></</span><span class="nt">ul</span><span class="p">></span>
<span class="p"><</span><span class="nt">ul</span> <span class="na">class</span><span class="o">=</span><span class="s">"stats"</span><span class="p">></span>
<span class="cp">{%</span> <span class="k">for</span> <span class="nv">tag</span> <span class="k">in</span> <span class="nv">article.tags</span> <span class="cp">%}</span>
<span class="p"><</span><span class="nt">li</span><span class="p">><</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">"#"</span><span class="p">></span><span class="cp">{{</span> <span class="nv">tag.name</span> <span class="cp">}}</span><span class="p"></</span><span class="nt">a</span><span class="p">></</span><span class="nt">li</span><span class="p">></span>
<span class="cp">{%</span> <span class="k">endfor</span> <span class="cp">%}</span>
<span class="p"></</span><span class="nt">ul</span><span class="p">></span>
<span class="p"></</span><span class="nt">footer</span><span class="p">></span>
<span class="p"></</span><span class="nt">article</span><span class="p">></span>
<span class="cp">{%</span> <span class="k">endblock</span> <span class="cp">%}</span>
</pre></div> </div> </div>
<div class="advertisement">
<a href="https://www.thedigitalcat.academy/freebie-first-class-objects">
<img src="/images/first-class-objects/cover.jpg" />
</a>
<div class="body">
<h2 id="first-class-objects-in-python-fffa">First-class objects in Python<a class="headerlink" href="#first-class-objects-in-python-fffa" title="Permanent link">¶</a></h2>
<p>Higher-order functions, wrappers, and factories</p>
<p>Learn all you need to know to understand first-class citizenship in Python, the gateway to grasp how decorators work and how functional programming can supercharge your code.</p>
<div class="actions">
<a class="action" href="https://www.thedigitalcat.academy/freebie-first-class-objects">Get your FREE copy</a>
</div>
</div>
</div>
<h2 id="next-steps-5961">Next steps<a class="headerlink" href="#next-steps-5961" title="Permanent link">¶</a></h2><p>As I promised, I showed you how to use Jinja tags and Pelican variables, and we went from a purely static template to a rich dynamic one. There are several things that you might want to investigate and implement now:</p><ul><li>Both <code>index.html</code> and <code>article.html</code> contain a great amount of common code (the part that displays the article). Try to work on that to isolate the shared code and remove the duplication. Remember that they are not exactly the same, so you might want to investigate the tag <code>with</code> provided by Jinja.</li><li>Tags and categories. Pelican creates pages with all the articles that belong to a specific category or tag, and they work exactly like the index page. The documentation of the variables available in those pages can be found at <a href="https://docs.getpelican.com/en/latest/themes.html#category-html">https://docs.getpelican.com/en/latest/themes.html#category-html</a> and <a href="https://docs.getpelican.com/en/latest/themes.html#tag-html">https://docs.getpelican.com/en/latest/themes.html#tag-html</a>. You should try to create a page that lists all the articles with a certain tag and connect it to the tag button at the end of each article.</li><li>Pelican can create pages of content (as opposed to articles), and you might want to show those in the navigation bar. You can find the documentation of the <code>Page</code> objects at <a href="https://docs.getpelican.com/en/latest/themes.html#page">https://docs.getpelican.com/en/latest/themes.html#page</a>. Create an "About me" page and link it there.</li><li>If you want to publish the website you probably want to minify assets to save bandwidth and reduce the loading time. Have a look at <code>webassets</code> (<a href="https://github.com/pelican-plugins/webassets">https://github.com/pelican-plugins/webassets</a>), a plugin that makes assets management as easy as pie.</li><li>Speaking of plugins, Pelican has a huge number of them. The developers are in the process of transitioning them to a new better format, so you will find the main plugins at <a href="https://github.com/pelican-plugins">https://github.com/pelican-plugins</a> and the rest at <a href="https://github.com/getpelican/pelican-plugins">https://github.com/getpelican/pelican-plugins</a>. I recommend having a look at <code>sitemap</code>, which is very easy to setup and provides an important tool for search engines to discover your site.</li><li>When it comes to deploying the static website you should definitely read <a href="https://docs.getpelican.com/en/latest/publish.html">Pelican's documentation</a>, as the management scripts support several backends.</li></ul><p>Last, but hopefully not least, the code of this blog is public and can be found at <a href="https://github.com/TheDigitalCatOnline/blog_source">https://github.com/TheDigitalCatOnline/blog_source</a>. While the overall setup contains a bit of legacy code (I started a while ago and many things have changed in the meanwhile), the theme <code>editorial</code> is pretty new, so feel free to have a look at it and to get inspired (<a href="https://github.com/TheDigitalCatOnline/blog_source/tree/master/editorial">https://github.com/TheDigitalCatOnline/blog_source/tree/master/editorial</a>).</p><p>I hope this was useful. Remember that Pelican is open source, and you can always get in touch with the maintainers to ask questions or to submit enhancements. Also remember to drop a line on Twitter to the author of any template you will use (thanks are always welcome) and to link to the source on the website. Happy blogging!</p><h2 id="feedback-d845">Feedback<a class="headerlink" href="#feedback-d845" title="Permanent link">¶</a></h2><p>Feel free to reach me on <a href="https://twitter.com/thedigicat">Twitter</a> if you have questions. The <a href="https://github.com/TheDigitalCatOnline/blog_source/issues">GitHub issues</a> page is the best place to submit corrections.</p>Run a blog with pelican2019-06-07T15:30:00+01:002019-06-07T15:30:00+01:00Leonardo Giordanitag:www.thedigitalcatonline.com,2019-06-07:/blog/2019/06/07/run-a-pelican-blog/<p>How to set up a static blog with Pelican, a step-by-step guide</p><p>One of the biggest piece of advice I can give to beginner developers is: write a blog.</p>
<p>Writing, and in general teaching, is a perfect way to understand concepts. Some say that you cannot claim you understood something until you can explain it properly. This unfortunately doesn't take into account that not everyone is a good communicator, and writing (also technical writing) is an art, not just a set of checkboxes to tick.</p>
<p>Nevertheless, explaining a concept forces you to try to organise your thought, to write them down in a sequential way, to explore corners that you take for granted while the concepts involved are all but simple.</p>
<p>So my advice is once again: write a blog. Share your experience as a programmer, mathematician, physicist, data scientist (and thousands of other interesting jobs that I can't mention here). Don't worry if you don't have a revolutionary discovery to share with others. We are standing on the shoulders of giants, and every little contribution is welcome.</p>
<p>One of my most successful posts on this blog is something I wrote after fighting for 3 hours with a trivial Python syntax mistake. I was already a senior programmer, I did a novice mistake. I shared the solution and now that post has a huge amount of visits every day, which hopefully means that some people stuck with the same problem can quickly find a solution. Maybe these people will one day write the new Google or the new AWS, and I'm glad I helped them today.</p>
<h2 id="pelican">Pelican<a class="headerlink" href="#pelican" title="Permanent link">¶</a></h2>
<p>I run this blog since 2013. I wanted to use a static website generator because I liked the simplicity of the concept, and since GitHub was providing free hosting on <a href="https://pages.github.com/">GitHub Pages</a> I considered it a viable option.</p>
<p>I started with <a href="https://jekyllrb.com/">Jekyll</a>, a very well-known static website generator written in Ruby, because it was the system used by the vast majority of technical bloggers out there at the time. Unfortunately I'm not a Ruby programmer, so every issue I had with the build system that ended in a crash was a mystery to me. I also wanted to add functionalities to the system, and the language once again was a barrier. Jekyll is surely a very good system but it didn't suit my needs.</p>
<p>Since I didn't have the time to study Ruby at that point, I tried to find a good static site generator written in Python, a language that I know, and I found it in <a href="https://blog.getpelican.com/">Pelican</a>. Arguably, the Pelican website is not graphically amazing, and this worried me a bit, but I quickly discovered that the whole system is pretty good.</p>
<p>In 6 years, with the help of Pelican, I developed a wonderfully simple blogging work flow based on Git, so I decided to share my Pelican setup with a Cookiecutter template. Recently I refurbished the template to update it with the latest changes that I made to my personal setup and I realised that, despite the documentation, setting up a blog based on pelican might still be difficult for some.</p>
<p>In this post I will show you how to create your blog from scratch using Pelican. You don't need to know Python to use it, even though, as it happened to me with Jekyll, it might help if you want to get involved in the development of the project.</p>
<p>You can also run Pelican without this template, just follow the <a href="http://docs.getpelican.com/en/latest/install.html">instructions</a> on the official documentation. My template simplifies the initial installation, and creates some script that make you follow a specific work flow, but you are free to change them to suit you needs.</p>
<p>If you are not acquainted with static web sites have a look at the <a href="https://en.wikipedia.org/wiki/Static_web_page">Wikipedia page</a>.</p>
<h2 id="prerequisites">Prerequisites<a class="headerlink" href="#prerequisites" title="Permanent link">¶</a></h2>
<p>You need to have <a href="https://www.python.org/">Python 3</a> and <a href="https://git-scm.com/">Git</a> installed in your system. <a href="https://github.com/petervanderdoes/gitflow-avh">Git Flow</a> is optional, so if you don't want to use it you can avoid installing it.</p>
<h2 id="github">GitHub<a class="headerlink" href="#github" title="Permanent link">¶</a></h2>
<p>You need to create two repositories in your GitHub account. The first one will host the source files of your blog (the <em>source</em> repository), while the second one will host the actual static site files (deploy repository). Follow the instructions <a href="https://help.github.com/en/articles/create-a-repo">here</a> if you are not sure how to create them.</p>
<p>Call the first repository <code>blog_source</code> and the second one <code><your_user_name>.github.io</code>. The former is just a convention followed by my template, while the latter is enforced by GitHub pages, which uses by default that repository to publish the website at the address with that name.</p>
<h2 id="install-the-template">Install the template<a class="headerlink" href="#install-the-template" title="Permanent link">¶</a></h2>
<p>Create a <a href="https://docs.python.org/3/tutorial/venv.html">Python virtual environment</a> and install <code>cookiecutter</code></p>
<div class="highlight"><pre><span></span><code>pip<span class="w"> </span>install<span class="w"> </span>cookiecutter
</code></pre></div>
<p>Then run <code>cookiecutter</code> on the template I prepared</p>
<div class="highlight"><pre><span></span><code>cookiecutter<span class="w"> </span>https://github.com/lgiordani/cookiecutter-pelicanblog.git
</code></pre></div>
<p>Now, you will be asked some questions, let's look at them in detail. Remember that you can always start from scratch of fix the values you entered manually later.</p>
<ul>
<li><code>github_username [yourusername]</code> - Well, this should be self-explanatory.</li>
<li><code>blog_source_repo [blog_source]</code> - This is just the name of the source repository that you created on GitHub. You can accept the default if you didn't change the name.</li>
<li><code>deploy_repository [yourusername.github.com]</code> - This is the name of the deploy repository, i.e. the one that contains the actual static website. The default value is already filled with your GitHub username, so if you are setting up a GitHub Pages blog you can just accept it.</li>
<li><code>deploy_directory [deploy]</code> - The local directory where the deploy repository is cloned and that will be updated by the deployment process. By default, this is set to <code>deploy</code> inside the project directory.</li>
<li><code>use_versioning [y]</code> - Say <code>y</code> if you want to have a release process for your website with a version number and associated Git tags.</li>
<li><code>use_git_flow [y]</code> - Say <code>y</code> if you want to initialise Git Flow on the repository (you need to have Git Flow already installed in the system).</li>
</ul>
<h2 id="set-up-the-environment">Set up the environment<a class="headerlink" href="#set-up-the-environment" title="Permanent link">¶</a></h2>
<p>Now enter the directory that was created by the template, install the requirements and run the <code>setup.sh</code> script</p>
<div class="highlight"><pre><span></span><code><span class="nb">cd</span><span class="w"> </span><blog_source_repo>
pip<span class="w"> </span>install<span class="w"> </span>-r<span class="w"> </span>requirements.txt
./setup.sh
</code></pre></div>
<p>This script performs the following actions</p>
<ul>
<li>it initializes git in the local repository, adding the source repository as a remote with the name <code>origin</code></li>
<li>if you decided to use Git Flow, it initializes the repository, creating the <code>develop</code> branch.</li>
<li>it clones the https://github.com/getpelican/pelican-plugins repository</li>
<li>it clones the https://github.com/getpelican/pelican-themes repository</li>
<li>it creates the <code>deploy</code> directory which is a local clone one of the deploy repository</li>
</ul>
<h2 id="configure-pelican">Configure Pelican<a class="headerlink" href="#configure-pelican" title="Permanent link">¶</a></h2>
<p>Now everything is ready to run the <code>pelican-quickstart</code> script.</p>
<div class="highlight"><pre><span></span><code>pelican-quickstart
</code></pre></div>
<p>This script asks the following questions. I marked with a <strong>!!!</strong> the answers that are not up to you but depend on the current setup</p>
<ul>
<li><code>Where do you want to create your new web site? [.]</code> - <strong>!!!</strong> Answer <code>pelican</code> so everything will be installed in that directory inside the current one, keeping the installation tidy.</li>
<li><code>What will be the title of this web site?</code> - This is up to you</li>
<li><code>Who will be the author of this web site?</code> - This is up to you</li>
<li><code>What will be the default language of this web site? [en]</code> - This is up to you</li>
<li><code>Do you want to specify a URL prefix? e.g., https://example.com (Y/n)</code> <strong>!!!</strong> Answer <code>Y</code></li>
<li><code>What is your URL prefix? (see above example; no trailing slash)</code> <strong>!!!</strong> This is <code>https://<username>.github.io</code> if you are using GH pages</li>
<li><code>Do you want to enable article pagination? (Y/n)</code> - This is up to you</li>
<li><code>How many articles per page do you want? [10]</code> - This is up to you</li>
<li><code>What is your time zone? [Europe/Paris]</code> - This is up to you</li>
<li><code>Do you want to generate a tasks.py/Makefile to automate generation and publishing? (Y/n)</code> - <strong>!!!</strong> Answer <code>Y</code></li>
<li>Answer <code>n</code> to all the following questions</li>
</ul>
<p>If you have questions on this part you can read the <a href="http://docs.getpelican.com/en/latest/install.html">Pelican documentation</a>.</p>
<p>Now you can enter the <code>pelican</code> directory and run <code>make devserver</code> which will run the development server at http://localhost:8000. <a href="http://docs.getpelican.com/en/latest/publish.html#make">This page</a> of the official documentation explains all the options of the Makefile.</p>
<h2 id="the-work-flow">The work flow<a class="headerlink" href="#the-work-flow" title="Permanent link">¶</a></h2>
<p>The work flow that you will follow using this setup is the following (I assume you use Git Flow, change the git commands accordingly if you are using another flow)</p>
<ol>
<li>Create a git branch: <code>git flow feature start <branch></code></li>
<li>Create one or more new articles / Edit previous articles: create the files as <code>pelican/content/<slug>.markdown</code></li>
<li>Commit: <code>git commit</code> (repeat 2 and 3 until you are satisfied with the results)</li>
<li>Merge the branch: <code>git flow feature finish</code></li>
<li>Release: <code>./release.sh</code> (this runs Punch to create a new release)</li>
<li>Deploy: <code>./deploy.sh</code> (this runs Pelican to create the static site and copies everything in the <code>deploy</code> directory)</li>
<li>Publish: <code>./publish.sh</code> (this adds, commits, and pushes the files in the <code>deploy</code> directory)</li>
</ol>
<p>Each one of these steps, with the notable exception of the second one, is performed through a single command and takes up to few seconds in the worst case. I prefer to have control on the publishing process, so often I run the git commands manually in the <code>deploy</code> directory, but you can safely use the provided Make directive.</p>
<h2 id="versioning">Versioning<a class="headerlink" href="#versioning" title="Permanent link">¶</a></h2>
<p>Versioning is not the most important thing to do in a blog, but I personally like to have a trace of what I created and when in my Git log. I use <a href="https://pypi.org/project/punch.py/">Punch</a>, a package that I developed to replace bumpversion. If you want to customise the default versioning scheme contained in the template read the <a href="https://punch.readthedocs.io/en/latest/">Punch documentation</a>.</p>
<h2 id="feedback">Feedback<a class="headerlink" href="#feedback" title="Permanent link">¶</a></h2>
<p>Feel free to reach me on <a href="https://twitter.com/thedigicat">Twitter</a> if you have questions. The <a href="https://github.com/TheDigitalCatOnline/blog_source/issues">GitHub issues</a> page is the best place to submit corrections.</p>