Last time I added the breadcrumbs for pages only. Today I decided to also add breadcrumbs to the posts - the approach is similar, but different in a few aspects. I will write down what I did below.

By Default Every Posts has Breadcrumbs

I am not adding the possibility of opting out the breadcrumbs for a specific post with a front matter variable. The site as it is right now will need crumbs for every post, so I choose not to add more code to the front matter for now. Then the post layout contains the following code:

<!-- _layouts/post.html -->
<!-- ... -->
  {% comment %} A post will always contain breadcrumbs {% endcomment %}
  {%- include breadcrumbs-posts.html -%}
<!-- ... -->

The Include File

Similar to the pages breadcrumbs, the include file is very simple, since the logic lives mainly in the ruby code and data file.

<!-- _includes/breadcrumbs-posts.html -->
<div id="breadcrumbs" style="margin-bottom: 1rem;">
<a href="/">Home</a>
    /
    {% for crumb in breadcrumbs %}
    <a href="{{ crumb.path | prepend:site.baseurl }}">
        {{ crumb.text }}
    </a>
    /
    {% endfor %}
<p href="#">{{page.title}}</p>
</div>

To notice: I find it a bit confusing that to extract the title from the front matter of a post using liquid it is necessary to use page.title (I keep making the mistake of writing post.title, which doesn’t work).

Logic Based On Post Categories

When adding the breadcrumbs for the pages, I added the breadcrumbs manually in the data file (because I have just a few pages). In the case of posts, I am only adding the breadcrumbs once per each category (which as of this date get assigned by using the post containing directory name). Some further relevant comments about this approach have been added together with the code below:

Jekyll::Hooks.register :posts, :pre_render do |post, payload|
    # get the post category
    # IMPORTANT - the code below works because:
    # - All posts contain a `categories` front matter.
    # - For the current site setup the `categories` variable contains only one category. 
    # - That category's breadcrumbs are provided in the corresponding data file.
    # - TODO: consider improving code by managing multiple categories per post.
    post_category = post.data["categories"][0] 
    if post.data["title"]
      puts "Pre render of post '" + post.data["title"] + "' of category '" + post_category + "'"
    else
      puts "Pre render of a post without a title"
    end
    payload["custom_variable"] = "custom_value" # this will be accessible with liquid as custom_value

    # get the breadcrumbs data file
    require 'json'
    breadcrumbs_data_path = File.join(Dir.pwd, '_data', 'breadcrumbs-posts.json')
    breadcrumbs_data_text = File.read(breadcrumbs_data_path)
    breadcrumbs_data = JSON.parse(breadcrumbs_data_text)

    # find the breadcrumbs for the current post in the data file (based on post category)
    breadcrumbs_found = false
    breadcrumbs_data.each do |member|
      if member["category"] == post_category
        puts "    Found breadcrumb data: #{member}"
        payload["breadcrumbs"] = member["crumbs"] # this will be accessible with liquid as {"path"=>"/journals/", "text"=>"Journals"}{"path"=>"/site-updates/", "text"=>"Site Updates"}
        breadcrumbs_found = true
        break # Exit the loop after finding the member
      end
    end

    if !breadcrumbs_found
      payload["breadcrumbs"] = nil # if not found it should be empty 
    end    
  end

If I stop to think about it for a minute, I am writing the names of the categories twice: once in the directory names, and once in the data file. The advantages I see when keeping this setup are flexibility and simplicity of code - I could add more ruby code and make it more automated, but writing breadcrumbs only once per category manually is ok for me for now, and who knows maybe later the need for restructuring the site arises.

Data File

For the sake of completeness, I add the full data file of post breadcrumbs, _data/breadcrumbs-posts.json, as of the date of today.

[
    {
        "category": "articles",
        "crumbs": [
            {
                "path": "/articles/",
                "text": "Articles" 
            }
        ]
    },
    {
        "category": "journal-cs",
        "crumbs": [
            {
                "path": "/journals/",
                "text": "Journals" 
            },            
            {
                "path": "/cs/",
                "text": "C# .NET" 
            }
        ]
    },   
    {
        "category": "journal-other",
        "crumbs": [
            {
                "path": "/journals/",
                "text": "Journals" 
            },            
            {
                "path": "/other/",
                "text": "Other" 
            }
        ]
    },
    {
        "category": "journal-revit-api",
        "crumbs": [
            {
                "path": "/journals/",
                "text": "Journals" 
            },            
            {
                "path": "/revit-api/",
                "text": "Revit API" 
            }
        ]
    },
    {
        "category": "journal-site-updates",
        "crumbs": [
            {
                "path": "/journals/",
                "text": "Journals" 
            },            
            {
                "path": "/site-updates/",
                "text": "Site Updates" 
            }
        ]
    },         
    {
        "category": "tutorial-one-page",
        "crumbs": [
            {
                "path": "/tutorials/",
                "text": "Tutorials" 
            } 
        ]
    },        
    {
        "category": "tutorial-vba",
        "crumbs": [
            {
                "path": "/tutorials/",
                "text": "Tutorials" 
            },
            {
                "path": "/vba/",
                "text": "Learn VBA" 
            }   
        ]
    },            
    {
        "category": "tutorial-git",
        "crumbs": [
            {
                "path": "/tutorials/",
                "text": "Tutorials" 
            },
            {
                "path": "/git/",
                "text": "Learn Git" 
            }            
        ]
    } 
]