Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Jekyll templates using django-like liquid blocks / inheritance

I'm getting into Jekyll in a big way and would like to use it as a general front-end development platform, but am running up against the limitations of the Liquid templating language, specifically its difference to Django templating.

I discovered the liquid-inheritance gem, which adds the all-important Extends and Block syntax from Django. This blog post extends the gem further to suit Jekyll's file system: http://www.sameratiani.com/2011/10/22/get-jekyll-working-with-liquid-inheritance.html

The problem is that it doesn't appear to implement blocks in exactly the same way Django does, which essentially renders the gem useless.

I have two jekyll "layouts" called - for the sake of understanding - parent.html and child.html. Neither of these contain YAML sections.

Parent

<html>
{% block foo %} {% endblock %}
</html>

Child

{% extends _layouts/parent.html %}
{% block foo %}
  <div>
    Bar comes next:
    {% block bar %} {% endblock %}
  </div>
{% endblock %}

And then I have a jekyll page which includes a YAML section thus:

---
title: test
---

{% extends _layouts/child.html %}
{% block bar %}My title is {{ page.title }} {% endblock %}

What I'd expect:

<html>
  <div>
    Bar comes next:
    My title is test
  </div>
</html>

What I get:

<html>
  <div>
    Bar comes next:
  </div>
</html>My title is test

It seems something is failing to treat the blocks in mypage.html as being eligible for insertion into the suitable places of parent/child, although it's clearly still doing something.

I'm not a ruby developer and am reasonably new to Jekyll, so I need help identifying what part of this stack is failing. The liquid-inheritance issues on github suggest others are experiencing this block nesting problem: https://github.com/danwrong/liquid-inheritance/issues/3

I've tried several of the forks of liquid-inheritance, many of which apparently fix that problem regex, but none seem to solve this.

Is what i'm tring to do fundamentally impossible? It seems like I'm at least 85% of the way there and the final bit needs fixing.

like image 400
xcession Avatar asked Oct 26 '12 12:10

xcession


1 Answers

I'm not sure this is ever going to work within Jekyll. I might be wrong, but here's my reasoning:

Each page is rendered out using do_layout in https://github.com/mojombo/jekyll/blob/master/lib/jekyll/convertible.rb

This works recursively - it processes the content of the page, then processes the page's layout, then that layout's layout and so on and so forth, passing the YAML variables up the chain (so they're always available in parent templates as {{ page.whatever}}).

This means that the only things which get passed up are the YAML values, and whatever the value of 'content' is after it has been processed by Liquid. I don't know how it is done elsewhere, but that seems incompatible with the idea of blocks, as they'd require you to pass up the two blocks separately.

Fundamentally, it seems to me that the issue is that Jekyll already has a simple form of inheritance - via the "layout" attribute that you can give to a layout. Fundamentally, I think that this is compatible with liquid-templating.

All that said, I'm not sure that you've exhausted the limits of using YAML, _includes, and template logic. If you're at the point of putting Django style blocks into your content, why not just do something like this:

Content:

---
title: some title
secondary_content: |
    Here is some *secondary* content that will be [markdownified](http://example.com).
    It can run to multiple lines and include
    * Lists
    * Good things
    * Etc
---

And here is the main content, as per usual

Template:

<html>
<article>
    <h1>{{ page.title }}</h1>
    {{ content }}
</article>
<aside>
{{ page.secondary_content | markdownify}}
</aside>

If you wanted to keep your templates clean, and have different content for different types of pages, you could use various includes:

Template:

<aside>
{% include sidebar_negotiation.html %}
</aside>

_includes/sidebar_negotiation.html:

{% if page.type = 'foo' %}
{% include sidebar_foo.html %}
{% else if page.type = 'bar' %}
{% include sidebar_bar.html %}
{% endif %}

And then put your page type specific stuff in those files. Obviously you could include it directly, but it is probably nice to abstract it out. Those includes will get all of the variables in the YAML.

If none of this is a win, you could always try Hyde: http://hyde.github.com/ which is written in Python, uses Jinja2 (basically Django templates++), and does the same sort of thing.

like image 142
heliotrope Avatar answered Nov 01 '22 01:11

heliotrope