To add a pinned post to a Jekyll website, you only have to modify one file (index.html), or two files (including main.css) if you want to highlight the pinned post in some way.

Before adding the pinned post, my index.html was very straightforward (heavily commented for pedagogical reasons):

---
layout: default
---

<div class="home">

   # create an unordered list with the CSS class "posts" (styled in the sites main.css)
  <ul class="posts">

    # Jekyll Liquid syntax for looping through site.post
     {% for post in site.posts %}

    <li>

      # format and display the post-date
      <span class="post-date">{{ post.date | date: "%b %-d, %Y" }}</span>

      # generate a clickable link (<a>) to the post.url, which is prepended with the site.baseurl, add that clickable link to the post.title, taken from the post frontmatter
      <a class="post-link" href="{{ post.url | prepend: site.baseurl }}"
        >{{ post.title }}</a
      >
      <br />

      # this Jekyll Liquid logic checks if there is a post.custom_excerpt in the posts frontmatter, and if so, displays it. If not, it displays the first paragraph of text from the post
      {% if post.custom_excerpt %}{{ post.custom_excerpt}} {% else %} {{
      post.excerpt }} {% endif %}
    </li>
    {% endfor %} 
  </ul>
</div>

This index.html treats all posts the same, but I needed a way for the site to treat pinned posts differently. There are many ways to do this, but the simplest I could find was to create the pinned post as a normal post in _posts, with the frontmatter tag pinned, and then scan through the posts to find the pinned posts, generate them first with custom css, and then go through again and generate the rest:

---
layout: default
---

<div class="home">
  

  <!-- Pinned Posts Section -->
  <!-- scan through posts to find posts tagged pinned, so they can be generated first, and with a custom css -->
  <ul class="posts">
    {% for post in site.posts %} {% if post.tags contains 'pinned' %}
    <li class="pinned">
      <span class="post-date">Pinned Post</span>
      <a class="post-link" href="{{ post.url | prepend: site.baseurl }}"
        >{{ post.title }}</a
      >
      <br />
      {% if post.custom_excerpt %}
      <p>{{ post.custom_excerpt }}</p>
      {% else %}
      <p>{{ post.excerpt }}</p>
      {% endif %}
    </li>
    {% endif %} {% endfor %}
  </ul>

  <!-- Normal Posts Section -->
  <!-- scan through posts again to find posts not tagged pinned, so they can be generated in order, with their normal css -->
  <ul class="posts">
    {% for post in site.posts %} {% unless post.tags contains 'pinned' %}
    <li>
      <span class="post-date">{{ post.date | date: "%b %-d, %Y" }}</span>
      <a class="post-link" href="{{ post.url | prepend: site.baseurl }}"
        >{{ post.title }}</a
      >
      <br />
      {% if post.custom_excerpt %} {{ post.custom_excerpt}} {% else %} {{
      post.excerpt }} {% endif %}
    </li>
    {% endunless %} {% endfor %}
  </ul>
  
</div>

The new class css pinned has to be defined. This can be done by adding something like the following to the main.css file:

.posts li.pinned {
  border: 1px solid #d3d3d3;
  background-color: #f9f9f9;
  padding: 5px;
  margin-bottom: 29px;
  border-radius: 3px;
}

You can pick any colours, padding, margin etc. you like, but I’m happy enough with this:

A Note on Jekyll’s Liquid Syntax

Jekyll uses the Liquid template language (originally developed by Shopify, based on Ruby) to generate static HTML websites from dynamic data. The main Liquid features required for specifying pinned posts are as follows:

Variables: Denoted by ``{{ … }}`, these represent dynamic content pulled from Jekyll’s data structures or post frontmatter.


{{ post.title }}

Tags: Denoted {% ... %}, these control logic and flow, such as loops and conditionals.


{% for post in site.posts %}

Filters: Filters use a pipe | to process the input on the left using the specified function or transformation on the right. In the following example the ouput of post.date is filterd using the format on the right.


{{ post.date | date: "%b %-d, %Y" }}

Conditionals: {% if ... %}, {% elsif ... %}, and {% else %} tags enable conditional logic.


{% if post.tags contains 'pinned' %}