Search code examples
rubyjekylljekyll-extensions

Overriding a context register in a Jekyll Block plugin


I'm trying to get more control over my post excerpts in Jekyll. Using the default excerpt code doesn't seem to work well in my case, as it (a) needs to be the first paragraph, and (b) is still rendered on the page. For most of my blog posts, I want either custom text, which isn't meant to be part of the actual blog post, or some text later on in the blog post. I was hoping to do this with a block, that can optionally take a parameter to render the content (although I'll add in that specific feature later). I've currently got this proof-of-concept plugin:

require "jekyll"

module Jekyll
  class RenderExcerptBlock < Liquid::Block
    def render(context)
      page = context.registers[:page]
      content = super

      page["excerpt"] = content.lines[0..50]

      content
    end
  end
end

Liquid::Template.register_tag "excerpt", Jekyll::RenderExcerptBlock

Which would theoretically let me do this:

{% excerpt %}
A snippet of this post
{% endexcerpt %}

However, this gives the error when running jekyll build:

  Liquid Exception: Key excerpt cannot be set in the drop. in /Users/nick.chambers/blog/_posts/2020-01-21-unix-shell-scripting-with-bash.md
             ERROR: YOUR SITE COULD NOT BE BUILT:
                    ------------------------------------
                    Key excerpt cannot be set in the drop.

Is it possible to override this register's value in some way? Alternatively, is there a more Jekyll way to achieve this?


Solution

  • The Jekyll way to have a custom excerpt for your post (or any document in a collection), is to simply add it to the front matter:

    ---
    title: Test Doc
    excerpt: This is a custom excerpt
    ---
    
    The opening paragraph of this document.
    
    Another paragraph in this document.
    

    Then reference it in your layout to render it:

    <div class="post-excerpt">
      {{ page.excerpt }}
    </div>
    

    or

    <div>
    {% for post in site.posts %}
      <h2>{{ post.title }}</h2>
      <div>{{ post.excerpt }}</div>
    {% endfor %}
    </div>