Detecting undated documents

I have a collection containing lots of documents. Some are dated via the front matter, some are dated via the filenames, and some aren’t dated at all. These last need to be treated specially: I need to avoid printing the date for them, obviously, but I also want them to sort last in any ordering by time, as if they were infinitely old.

It appears that undated documents get assigned today’s date (that is, the value of site.time). I can detect whether I’m looking at an undated document by doing {% if page.date == site.time %}. This works fine, but of course the documents are infinitely new, so appear at the top of any list ordered by date. I’d rather like to avoid this.

So far I’ve tried:

  • setting site.time to the unix epoch. This causes 90% my documents not be rendered. Apparently site.time is used internally somehow; I’m not sure how, but it’s obviously not right.

  • setting a default time in the _config.yaml for the collection. This works, but it overrides the date detected from the filename. I don’t want that.

  • monkeypatching Jekyll.Document.date to return Time.at(0) if the document is unset. This almost works… but now page.content starts returning the raw Markdown or HTML content rather than the rendered version!

Any suggestions? Modifiying the front matter of my documents isn’t an option.

What I’d really like is for undated documents to have page.date unset, so I can just do {% if page.date %} in my logic…

why not do two loops? one for date = site time and the other for it not being equal?

From what I can tell you are trying to do two things:

  1. list all documents (do two loops so the undated ones are last)
  2. not show the date within a document that has no date (already figured out)

Your findings seem a little unexpected to me, could be a bug.

I’ve figured out, I think, why my page.content is unrendered — it’s because the unrendered content gets replaced with rendered content as pages are processed, and whether you see rendered or unrendered depends entirely on the page processing order. My monkey patch is obviously changing the render order.

That suggests that the patch is actually working, but I’ve got problems elsewhere due to depending on the render order.

You’re quite right about using two loops; that would have worked nicely. As the render order would be unchanged, I’d still see the rendered output (I’m using it to generate excerpts). However it would only be working accidentally, so I would still need to fix it…

Yep, this was a combination of both issues.

To fix, I needed this plugin:

require "time"

module Jekyll
    ANCIENT = Time.at(0)

	class AncientnessGenerator < Generator
		safe true
		priority :high

        def generate(site)
            site.collections["pages"].docs.each do |page|
                page.data["ancient"] = (page.date == ANCIENT)
            end
        end
    end

    class Document
        def date
            data["date"] ||= ANCIENT
        end
    end
end

…and then I could reason about pages like this:

{% if page.ancient %}
  very old
{% else %}
  {{ page.date | date: "%Y %B %d" }}
{% endif %}

My page.content issue was caused by the Jekyll rendering order; the docs in the ‘Order of Interpretation’ page are in fact wrong, and each page is processed in its entirety before moving onto the next, rather than doing all the Liquid, then all the Markdown, then all the layouts, etc. (I’ve filed a bug.) The only way round that was to rearrange my source files so that the page which needed the HTML content was always rendered after the collections it was taking the content from.

But it all looks like it’s working now.