36
votes

I want to build documentation site using Jekyll and GitHub Pages. The problem is Jekyll only accept a filename under _posts with exact pattern like YYYY-MM-DD-your-title-is-here.md.

How can I post a page in Jekyll without this filename pattern? Something like:

  • awesome-title.md
  • yet-another-title.md
  • etc.md

Thanks for your advance.

4

4 Answers

38
votes

Don't use posts; posts are things with dates. Sounds like you probably want to use collections instead; you get all the power of Posts; but without the pesky date / naming requirements.

https://jekyllrb.com/docs/collections/

I use collections for almost everything that isn't a post. This is how my own site is configured to use collections for 'pages' as well as more specific sections of my site:

My config.yaml

My Pages collection

27
votes

I guess that you are annoyed with the post url http://domaine.tld/category/2014/11/22/post.html.

You cannot bypass the filename pattern for posts, but you can use permalink (see documentation).

_posts/2014-11-22-other-post.md

---
title:  "Other post"
date:   2014-11-22 09:49:00
permalink: anything-you-want
---

File will be anything-you-want/index.html.

Url will be http://domaine.tld/anything-you-want.

5
votes

What I did without "abandoning" the posts (looks like using collections or pages is a better and deeper solution) is a combination of what @igneousaur says in a comment plus using the same date as prefix of file names:

  1. Use permalink: /:title.html in _config.yml (no dates in published URLs).
  2. Use the format 0001-01-01-name.md for all files in _posts folder (jekyll is happy about the file names and I'm happy about the sorting of the files).

Of course, we can include any "extra information" on the name, maybe some incremental id o anything that help us to organize the files, e.g.: 0001-01-01-001-name.md.

-2
votes

The way I solved it was by adding _plugins/no_date.rb:

class Jekyll::PostReader
  # Don't use DATE_FILENAME_MATCHER so we don't need to put those stupid dates
  # in the filename. Also limit to just *.markdown, so it won't process binary
  # files from e.g. drags.
  def read_posts(dir)
    read_publishable(dir, "_posts", /.*\.markdown$/)
  end
  def read_drafts(dir)
    read_publishable(dir, "_drafts", /.*\.markdown$/)
  end
end

This overrides ("monkey patches") the standard Jekyll functions; the defaults for these are:

# Read all the files in <source>/<dir>/_drafts and create a new
# Document object with each one.
#
# dir - The String relative path of the directory to read.
#
# Returns nothing.
def read_drafts(dir)
  read_publishable(dir, "_drafts", Document::DATELESS_FILENAME_MATCHER)
end

# Read all the files in <source>/<dir>/_posts and create a new Document
# object with each one.
#
# dir - The String relative path of the directory to read.
#
# Returns nothing.
def read_posts(dir)
  read_publishable(dir, "_posts", Document::DATE_FILENAME_MATCHER)
end

With the referenced constants being:

DATELESS_FILENAME_MATCHER = %r!^(?:.+/)*(.*)(\.[^.]+)$!.freeze
DATE_FILENAME_MATCHER = %r!^(?>.+/)*?(\d{2,4}-\d{1,2}-\d{1,2})-([^/]*)(\.[^.]+)$!.freeze

As you can see, DATE_FILENAME_MATCHER as used in read_posts() requires a date ((\d{2,4}-\d{1,2}-\d{1,2})); I put date: 2021-07-06 in the frontmatter.

I couldn't really get collections to work, and this also solves another problem I had where storing binary files such as images in _drafts would error out as it tried to process them.

Arguably a bit ugly, but it works well. Downside is that it may break on update, although I've been patching various things for years and never really had any issues with it thus far. This is with Jekyll 4.2.0.