Include Jekyll template ONLY if it exists - ruby

There's this answer in another question, but it doesn't meet my needs.
I need to include a template in _includes if and only if it exists.

This might come handy for you.
The basic idea is to place the include block within a capture block in order to save its content to a variable.
If the template doesn't exists, the variable will contain an error message rather than the templates content, otherwise you're good to go to include the actual template.
{% capture the_snippet_content %}{% include the_snippet %}{% endcapture %}
{% unless the_snippet_content contains "Liquid error" %}
{{the_snippet}}
{% endunless %}

Related

Jekyll: including a post inside another post

Does Jekyll provide a way to include a post inside another post? I know that sounds a bit goofy, but I'm using it for a cooking/recipe site. Some of my recipes are made up of components, or other, smaller recipes.
I'm looking for a way to include a handful of posts inside another post, complete with template and all. Is this possible?
I did a ton of googling, and found I was only able to include into a page, not post, and it didn't use the default liquid template, just plain markdown.
Ideas?
I used Jekyll's Collections in my website to solve a problem similar to yours.
Collections are still an experimental feature in Jekyll, and the solution I used is pretty hacky by itself, but if you don't go too crazy with it it's manageable enough.
For a more detailed and friendly intro to collections, here's a great post about getting started with them.
One thing we need to have in mind is that we should get away from posts for cases like this.
As mentioned by Ben Balter in the link above, “If people are using blog posts for a non-blog post thing, Jekyll has already failed”. Recipes are not posts, and we should avoid using them as such if we can.
With that said, here's my approach in three steps:
Create two collections (our custom post types) — let's say these are “Recipes” and “Ingredients”
Find a way to relate them to each other — To make sure “lettuce” will be listed under “salad”
Include the relevant “Ingredients” in your “Recipes” — Adding the liquid code to actually display information from “lettuce” somewhere in the “salad” page.
Step 1
Create _ingredients and _recipes folders for each of your collections (make sure to name them in plural) and add them to your _config.yml file:
collections:
ingredients:
output: true
recipes:
output: true
permalink: /recipes/:path/
The output: true parameter creates an individual HTML page for each item in the collection and permalink (optional) lets you control the URL.
Step 2
Add a piece of metadata like this to the YAML front-matter of your lettuce.md collection item:
---
parent-collection: salad
---
If lettuce.md belongs to more than one recipe, you can add more than one. Make sure to add content below the metadata if you need a description:
---
parent-collection:
- salad
- hamburguer
- taco
---
Lettuce is really good for your health, but it kinda sucks as a food.
Note that salad, hamburguer and taco should named exactly like the recipe URL slug or this won't work (i.e. greatrecipes.com/recipes/salad). If you have a recipe name that's a sentence, you wrap it in quotes.
This variable will be slugified later on, so a name like parent-collection: The Amazing Souflè Français will match the-amazing-soufle-francais. Still, weird stuff happens: when in doubt, just write smallcaps salad.
This is the hacky part.
Step 3
Create a specific layout for your recipes (like _layout/recipe-page.html) and add the code below — this is where we'll include the ingredients into the recipe page.
Remember your recipes (salad.md and friends) should be pointing to this layout.
{% capture current_collection %}{{ page.url | remove: "recipes" | remove: "/" | remove: " " }}{% endcapture %}
Here we capture the name of the recipe from the URL and assign it to the current_collection variable. Make sure this in a single line because making it multi-line will add a bunch of whitespace to the captured string and break your code 10/10 times. Insane.
<div class="recipe-content">
<p>{{ content }}</p> -- This is the content of the current recipe in the collection, your "post text".
</div>
{% for ingredient in site.ingredients %}
{% capture captured_parent_collection %}{{ ingredient.parent-collection | slugify }}{% endcapture %} -- This capture is just to pass the slugify filter and sanitize parent.collection to make sure it matches the URL slug
{% if captured_parent_collection == current_collection %}
<div class="recipe-ingredient">
<h3>{{ ingredient.name }}</h3> -- "<h3>Lettuce</h3>"
<p>{{ ingredient.content }}</p> -- "<p>Lettuce is really good for your health, but it kinda sucks as a food.</p>"
</div>
{% endif %}
{% endfor %}
Match the ingredients for this recipe and includes each one of them into the layout. YASS!
Each of your ingredients should be appearing right under your recipe text.
Note that you're not pulling the ingredients inside the recipe text like you described in your question, but including them in the layout after it. As far as I know you can't really add things in the middle of your post/collection text — unless you hack your way through a custom plugin for Jekyll.
There are certainly less hacky ways to do this, but this is how I made it work. Let me know if you find any trouble trying this for yourself — and anyone else, feel free to correct me.
I have this setup going on in my site — take a look at the layout where I pull in my child collection items and the metadata on the child collection items themselves.
I stumbled upon this question while looking for a way to do this, and here's what I ended up doing. I figured I'd post it in case somebody else is looking for a way to do this as a one-off and doesn't feel like creating a whole collection.
In the post where you want to include your other post, you can use Jekyll's where filter to get a reference to your other post, and then print that post's content:
---
layout: whatever
---
Your original post's content here.
{% assign myOtherPost = site.posts | where:"url", "/other/post/url" | first %}
{{ myOtherPost.content }}
Some more content here.

Preventing category downcasing in octopress

I've been using Octopress for a while, but I haven't pulled upstream changes for ages. I just made a new local branch to do so, and the merging was pretty painless, but one problem I have is that my category names are now downcased everywhere. This didn't use to happen, and it's a problem for me because I colorize links differently based on the category of each post, using the following:
{% capture category_class %}
{% for category in post.categories %}
{{ category | prepend:'category-' }}
{% endfor %}
{% endcapture %}
# ...
<div class="{{ category_class | strip_newlines }}">
Here, the category_class ends up being something like "category-coding" even though the category is specified in the post source as Coding, with a capital C. Now, I could just change my SASS to use lowercase category names for the classes... but then my category names would still be lowercase everywhere else, and I'd prefer them not to be.
So I'd like to remove this downcasing of category names throughout Octopress. But I can't for the life of me figure out where it is actually happening. (It probably doesn't help that I don't know Ruby.)
There's a downcase call in Jekyll which produces the lowercased categories:
https://github.com/jekyll/jekyll/blob/v2.5.3/lib/jekyll/post.rb#L83
def populate_categories
categories_from_data =
Utils.pluralized_array_from_hash(data, 'category', 'categories')
self.categories = (Array(categories) +
categories_from_data).map {|c| c.to_s.downcase}.flatten.uniq
end
There doesn't seem to be any other way to access the categories array within a post. You would need to modify or monkey patch Jekyll yourself or just use Javascript or CSS (text-transform) to re-capitalize.
It seems Octopress also supports plugins, so that could be one more solution if you want to do some custom Ruby hacking. I.e. create a capitalized categories plugin.

Jekyll / Liquid include files dynamically

currently I'm working on a new site with Jekyll and have some kind of problem there. I have a layout page, where I can define the background image with variables from each page.
Layout:
class="background background-{{ page.header_bg }}"
Page:
---
header_bg: storm
---
But now I want to include some file dynamically, depending on the variable value. Well, I can do it with some if or case statements, but actually I want to do something like
{% include page.header_bg %}
But this does not work, because Jekyll is looking for a file, that is called "page.header_bg" and not the value.
Can some one help me please?
According to the docs, you need to put the variable name inside additional {{ }}.
Quote from the link:
ProTip™: Use variables as file name
The name of the file you wish to embed can be literal (as in the
example above), or you can use a variable, using liquid-like variable
syntax as in {% include {{my_variable}} %}.
I know this question is 6 years old but here's a clear answer for posterity. You need to assign page.header_bg to a variable first and then use the variable in the include statement.
{% assign headerBg = page.header_bg %}
{% include headerBg %}
You will get an error Liquid Exception: Invalid syntax for include tag if you attempt to use page.header_bg directly in the include statement.

Explain structure of site.categories

Jekyll supplies a site.categories variable that is accessible to liquid templates. In my site I currently have two categories with one post each. From looking at the jekyll bootstrap categories.html I know:
{% for category in site.categories %}
{{ category[0] }}
I know this renders to the category's name. However if I also do:
{% for item in category %}
{{ item }}
It seems category has two items: its name and the post. This makes no sense to me. category[0] is name and then an array of posts starts at index 1? Why does this make sense? I wonder if this comes from Ruby somehow, but I don't know Ruby. (Since Jekyll is written in Ruby I'm adding this tag, since I suspect much of the syntax is derivative.)
How do I determine the structure of site.categories? I don't know how to debug this and don't understand liquid syntax well enough to know why this behavior makes sense.
site.categories is a multi-dimensional array of categories. Each category consists of it's name as first element, and a list of posts contained in that category. The posts themselves consist of their name, content, permalink and more (the same info as in site.posts entries).

array in config parsed different from local and server

I have the following in my _config.yml:
slides: [1,2,3]
Then I iterate over it on my view:
{% for i in site.slides %}
// dummy slide
{% endfor %}
It works fine on my local dev machine, the dummy slide is shown thrice, but on github pages it's only shown once. Do you guys know why? Could this be a version problem?
There is very “strict” version of YAML parser there on github. The almost same question was already asked.
I would suggest you to use the standard YAML notation for arrays:
slides:
- 1
- 2
- 3
Hope this helps.

Resources