Twitter Email
subspace (/ˈsʌbspɛɪs/)
A Jekyll playground site

Jekyll personal FAQ

Author: AlexVie
Title: Jekyll personal FAQ
Language: en-US
Number of words: 1322
Created: 22:45 on Tuesday, 22. August 2017
Modified: 15:35 on Monday, 02. October 2017
Excerpt:

This is a list of questions (and answers) I stumbled over while working with Jekyll. It is by no means a complete list and will most likely cover topics that are already documented elsewhere. I found many answers on stackoverflow questions tagged with Jekyll and links are given when still available. As almost always with such matter, stackoverflow is the #1 resource for such questions.

Page layout: default_dyn
Last modified:
22:45 | by AlexVie in JekyllSite
Reading time: approx. 0 minute(s).

This is a list of questions (and answers) I stumbled over while designing this site. It is by no means a complete list and will most likely cover topics that are already documented elsewhere. I found many answers on stackoverflow questions tagged with Jekyll and links are given when still available. As almost always with such matter, stackoverflow is the #1 resource for such questions.

How to filter posts in a loop

Suppose you want to iterate over the collection of posts in the paginator and filter by a some criteria defined by the page’s FrontMatter. Here we are looking for posts which have a variable myvariable defined and set to true in their FrontMatter block.

1
2
3
{% for post in paginator.posts | where:"myvariable",true %}
    [...]
{% endfor %}

This won’t work, because filters are not allowed in the for loop.

1
2
3
4
{% assign posts = paginator.posts | where:"blog",true %}
{% for post in posts %}
    [...]
{% endfor %}

The fix is first assign the filtered collection to a new variable and then iterate over it.

Parse markdown in HTML content

Markdown allows the usage of HTML tags and therefore to mix HTML and ordinary text within a single post or article. By default, markdown will not parse inside HTML tags, which is usually the desired behavior, but sometimes you may want the exact opposite and parse inside HTML tags. Consider, you want to use a <div> section for highlighting a paragraph with a custom CSS class or similar purpose like I did in this paragraph for which I assigned a 2-column CSS layout by simply wrapping it in <div> tags.

1
2
3
4
5
6
7
8
9
<div class="myclass">
    the paragraph's content (written in markdown)
</div>
   <!-- content above will be taken as raw HTML, no markdown processing will happen. -->

<div class="myclass" markdown="1">
    the paragraph's content
</div>
   <!-- here, markdown will parse it.-->  

Note that the above only works with the kramdown markdown converter, not with alternatives like redcarpet. Kramdown is the default in Jekyll 3, so you shouldn’t need to worry unless you tweak your configuration towards a non-standard setup.

Escape liquid tags when highlighting code

If you need to highlight a code block containing liquid tags, you have to “escape” it. By default, liquid tags are parsed in markdown content and this includes a block defined for syntax highlighting. You have to enclose the liquid code in [% raw %] … [% endraw %] tags (note, I have to use square brackets here, otherwise the tags wouldn’t show up) to prevent it from being parsed instead of just highlighted. The raw tag was a plugin in older versions of Jekyll but is now included in Jekyll 3.

Accessing front matter variables in the post

All variables defined in the FrontMatter of any article are available as members of the page object. If FrontMatter defines the title then you can access it via {{ page.title }} in the post. In a similar way you can access these variables when iterating over post collections in a loop.

All configuration variables defined in the site configuration (_config.yaml) are available in the site namespace.

When exactly is a FrontMatter block necessary?

Basically, for all pages that become content pages. It doesn’t matter whether the page is a markdown document or plain HTML - if it’s going to become its own page, it needs a FrontMatter block. Layouts do not need any and neither do fragments that are included, because technically, they become a part of the page that includes them.

Check whether the current item is the last in an iteration

1
{% unless forloop.last %},&nbsp;{% endunless %}

The unless statement outputs everything between it and the next endunless as long as the condition does not evaluate to true.

Iterate over categories and capture the name

1
2
3
{% for category in site.categories %}
   <h3><a href="[....]{{ category | first | strip_html | downcase}}/index.html">{{ category | first | strip_html | tolower}}</a></h3>
{% endfor %}

Parse markdown in a Frontmatter variable.

Normally, front matter content is not parsed, but you can always use the markdownify filter to parse anything you want.

Let’s assume, you have defined an excerpt via front matter, a couple of lines and you want to include a hyperlink and some simple markup.

Solution:

   {{ post.excerpt }}                 // raw content, "as is"
   {{ post.excerpt | markdownify }}   // fully parsed

Apply multiple style attributes

This is possible by simply adding them one by one. For block level elements (e.g. paragraphs) they must be separated by newlines.

My paragraph text...[...]
{:bold}
{: .indent}

This applies both the predefined attribute bold and the CSS class .indent to the paragraph. Similar constructs are possible for span level elements. Here, two classes were applied to the word span, one defining the text-decoration: underline; and a second one setting the red color.

It is also possible to include style definitions. Just create a .markdown file in _includes, say defs.md, that holds all the style definitions, like so:

{:cols: .two_cols}
{:red: .c_red}
{:blue: .c_blue}
{:green: .c_green}
{:un: style="text-decoration: underline;"}
{:ileft: style="padding-left: 20px; border-left: 3px solid #ccc"}
{:iright: style="padding-right: 20px; border-right: 3px solid #ccc"}

You can then include that file in any article by simply placing a {% include defs.md %} at the beginning of the document and use the pre-defined style attributes.

Loop over a collection with the name given in a variable?

You want to iterate over all documents in the collection when the name of the collection is given in the variable page.collection.

{% for collection in site.collections %}
    {% if collection.label == page.collection %}
        {% assign pages = collection.docs | where: "tags", "first" | sort: 'modified' | reverse %}
        {% for page in pages limit: 5 %}
            {% include sidebar/document_entry.html %}
        {% endfor %}
        {% break %}
    {% endif %}
{% endfor %}

Access all documents on the site.

Use site.documents

{% assign docs = site.documents | where: 'tags', 'first' | sort: 'modified' | reverse %}

This gives you an array, containing all posts, pages and collection items tagged with first and sorted by the modified: front matter field in reverse order (newest first).

How to avoid auto-numbering in numbered lists

The following markdown code should produce a numbered list starting with the number 4. But this doesn’t work.

4. four
5. five

It will produce the following output:

  1. four
  2. five

This is because markdown will auto-number lists always starting with 1. This can be avoided by explicitly specifying the start value before the first list item:

{:start="4"}
4. four
5. five
  1. four
  2. five

Will produce the desired output.

How to concatenate strings

Use the capture keyword.

{% capture foo %}{{site.foo}}{{site.bar}}{% endcapture %}

Creates a new variable foo containing the result of site.foo + site.bar concatenated.

Access data elements via variables

Suppose you have a list of images in site.data.gallery and you want to access one of the images via a page variable, say image. This is possible by using the bracket notation, for example site.data.gallery[page.image]. Assume page.image contains the string foo, then that notation would be the same as writing site.data.gallery.foo. If your data elements have additional attributes, it’s possible to access them as site.data.gallery[page.image].description.

However, you cannot pass such a construct as parameter to a include statement. You need to assign it first, like so:

{% assign image = site.data.gallery[page.image] %}
{% include foo.html image=image %}

You can then use the element normally as include.image in your include fragment.