Trying to get a collection from a Front Matter value - jekyll

Hi I'm new to Jekyll and have a basic blog set up. Now my idea is to loop through a collection per blog post to get some fancy HTML going on. Because as far as I'm aware you can't simply add HTML to the markdown.
// config.yml
collections:
- hollowknight
So I've set up a collection named hollowknight and I got a blog post about Hollow Knight.
In the Front Matter of the blog post I have collectionid: 'hollowknight'. And in the Layout I use for blog posts I tried the following:
// post.html
{% capture collection %}site.{{ page.collectionid }}{% endcapture %}
{% for section in collection %}
{{ section.title }}
{% endfor %}
So the idea was to set the collection variable to site.hollowknight as configured in the config and the Front Matter. I set up a single article inside the collection, but it isn't showing up.
Is there any way to realise this?
Edit: https://talk.jekyllrb.com/t/list-collection-with-name-from-front-matter/3619/6
Or is there a way to use paragraphs in the Front Matter, because then I could just use arrays and objects in the Front Matter of the posts to do my magic?
Edit: https://github.com/jekyll/jekyll/issues/246#issuecomment-1639375
Or am I just stretching to far from what Jekyll is supposed to be?
Edit
So I found out I was getting the collection the wrong way, https://talk.jekyllrb.com/t/list-collection-with-name-from-front-matter/3619/6.
{% for section in site.[page.collectionid] %}
{{ section.content | textilize }}
{% endfor %}
The only weird part is, everywhere I see | textilize being used but can't get it to work.

This is the final solutions:
{% for section in site.[page.collectionid] %}
{{ section.content | markdownify }}
{% endfor %}
It's markdownify instead of textilize.
Also I ended up using a Front Matter array with objects to loop through instead of a collection to keep it more organized.

Related

Searching for page in site.pages by path without iteration

I have a path to some page from root in Jekyll as a variable path. I want to get some variables from FrontMatter of that page. How could I find this page in site.pages without iterating over all pages?
I mean something like
{% assign aim = site.pages[path] %}
instead of
{% for p in site.pages %}
{% if p.path == path %}
{% assign aim = p %}
{% endif %}
{% endfor %}
Will this solution be faster for a site with a thousand of pages?
You can use the where liquid filter for this:
{% assign aim = site.pages | where:"path",path %}
Thanks #β.εηοιτ.βε for the hint!
That was what I expected, but when I used this template, I've faced the problem: the output of {{aim.title}} was empty.
The where filter produces list even it consists of just one element! But each filepath in a file system points exactly at one file, so I expected that aim will be the page, not a list. To fix this, I've added first filter:
{% assign aim = site.pages | where:"path",path | first %}
And now aim is the page variable I am searching for.
About speed. This solution builds a site 2X faster on my hardware.

How to use Liquid include variable within a for loop?

I have this Liquid template which looks like this:
# /_includes/slideshow.html
{% for image in {{ include.images }} %}
...
{% endfor %}
which I'm trying to use with a YAML file (for my Jekyll site) like this:
# /index.md
{% include slideshow.html images='site.data.homepage_images' %}
The reason I see this failing is because my include variable {{ include.images }} resolves to a string within the for loop. Is there a different way to accomplish this? I'm still rather new to Liquid, YAML, Jekyll, and well, web development altogether, so any help in doing this is much appreciated!
(Note: the problem goes away if I replace {{ include.images }} with site.data.homepage_images.)
Additionally, the reason why I'm doing this (and why that crude fix isn't the solution I'm looking for) is for the ability to inject my image slideshow elsewhere around my site. It'd save a lot of code to abuse my include variable in this way.
Correct syntax in for loop is : {% for image in include.images %}

Random access contents of Jekyll collection

I'm using a Jekyll collection to generate a reveal.js presentation. Each file in the collection represents one slide and are named sequentially, eg 01.md, 02.md, etc. This all works fine but I want to find a more flexible method to order slides.
If I can randomly access the files in the collection, rather than sequentially iterate through them, I could maintain the order of slides external to the collection - something like: [0,1,3,2,4].
Where the collection is defined as:
collections:
reality:
title: Reality Slide Deck
output: false
I can get the content of item 3 of the collection with:
{{site.reality[3].content}}
How do I access the front matter?
Thanks in advance.
Any front matter's variable is available under is own name.
{{site.reality[3].title}}
or
{{site.reality[3].variableName}}
You can loop through the content of your site using site.collection as is explained in the documentation at https://jekyllrb.com/docs/collections/#documents
To access only one collection you can use a conditional statement.
{% for info in site.collections %}
<ul>
<li>{{ info }}</li>
<li>The name of the collection: {{ info.label }}</li>
{% for stuff in info.docs %}
<li>{{ stuff.title }}</li>
{% endfor %}
</ul>
{% endfor %}
After saying all of this you can of course just loop through the one collection as below:
{% for real in site.reality %}
<li>{{ real.title }}</li>
{% endfor %}
The only other method that may work it to create an array using liquid syntax
{{ "a~b" | split:"~" }} #=> ['a','b']
Not sure if this answers your question, I hope it's useful for someone.

Wildcard match in Liquid tag?

I'm trying to filter out part of a post from my site's RSS feed. I want the rest of the post, but just want to remove certain parts.
Is there a way to filter this out somehow? I've looked at these Liquid tags/filters, and the closest I've found were remove and replace, but they seem to match literally.
I'm trying to basically do this in my feed.xml:
{{ post.content | replace:'<span class="no-rss">*</span>','' | cdata_escape }}
Is there some way to use a wildcard in these filters, or achieve this otherwise that I'm not aware of? My Google-fu has run dry on this one.
Two solutions :
using excerpt with posts
Part of the post you want to inject in your feed is at the beginning of your post.
Use excerpt
isolating part of content with liquid filters
If you are in a page (they don't have excerpt), or in a post and want to select specific part of your content, you can use liquid filters.
string.split and array filters.
In any post or page
---
your front matter variables here
---
Head of my document
<!-- start -->
Text to extract
<!-- end -->
Bottom of my document
in your rss
{% for p in site.posts %}
{% if p.content contains "<!--start-->" %}
{% assign extract = p.content | split: "<!--start-->" | last | split: "<!--end-->" | first %}
{{ extract }}
{% else %}
{{ p.content }}
{% endif %}
{% endfor %}
Instead of removing the whole span you could get rid of the style class being applied to it:
{{ post.content | remove: ' class="no-rss"' | cdata_escape }}

Strip url to 1 word in Jekyll

I am building a Jekyll blog, and I have come across an issue with permalinks.
My permalinks to blog posts are set like this in
_config.yml:
permalink: /:page/:categories/:title
It outputs like this when navigating to a blog post:
http://localhost:4000/blog/travel/netherlands-trip-prequesites/
I have some static pages in the site: Blog, Travel
The variable page.url outputs this url: /blog/travel/netherlands-trip-prequesites
The code my navigation bar uses to highlight the current page (giving it an "active" class):
{% assign url = page.url|remove:'index.html' %}
{% for nav in site.navigation %}
{% if nav.href == url %}
<li class="active">{{nav.name}}</li>
{% else %}
<li>{{nav.name}}</li>
{% endif %}
{%endfor%}
It works great when navigating to static pages, however when I click a blog post it doesn't highlight the correct static page. (ex.: If i navigate to a blog post with the url /blog/smth/title it should automatically highlight "Blog" in my navigation. When I navigate to /travel/smth/title it should highlight "Travel")
What I'd like to do is to strip down the output of page.url to its first part. For example I'd like to stip the following output
/blog/travel/netherlands-trip-prequesites
down to
/blog/
Why? So I can use it to check which static page it belongs to and highlight it accordigly.
The easiest way is to use split:
{{ page.url | split:'/' | first }}
That will give you the URL content up to the first / character.
I managed to solve it with three filters:
{{ page.url | replace:'/',' ' | truncatewords: 1 | remove:'...' }}
page.url outputs: /page/cat/title, then replace removes the forward slashes producing: page cat title. truncatewords truncates the string down to one word, producing: page... (for some reason three dots gets inserted after the remaining word). After all this I only needed to remove those dots with remove and voilá, my final string: page.
Hope this helps someone.
The answer provided by PeterInvincible was almost perfect, however, there's no need to get piping to remove involved...
The following also will produce desired output
{{ page.url | replace:'/',' ' | truncatewords: 1,"" }}
And to save it to a variable use capture redirection
{{ capture url_base }}{{ page.url | replace:'/',' ' | truncatewords: 1,"" }}{{ endcapture }}
Which can be called via {{url_base}} or mixed with other processing calls.
Also for file paths instead of URLs page.dir works well if you're not using permalink settings for layout, check the gh-pages branch (specifically _includes/nav_gen.html for functional, though rough'round the edges, example) for hosted examples of similar code examples related to liquid syntax and other magic.
Edits & Updates
The above linked script is now live/mostly-working/modular and auto-serving parsed sub-directories viewed currently at the related https://s0ands0.github.io/Perinoid_Pipes/ project site providing examples of recursive parsing of directories. Including and modding for nearly any theme should be possible just check the commented section at the top for currently recognized commands that maybe passed at inclusion call... on that note of inclusion and modularization here's how to turn the above example code for directory parsing into a function
{% comment %}
# Save this to _include/dir_path_by_numbers.html
# import with the following assigning arguments if needed
# {% include dir_path_by_numbers.html directory_argument_path="blog" directory_argument_depth=1 %}
{% endcomment %}
{% assign default_arg_directory_path = page.url %}
{% assign default_arg_directory_depth = 1 %}
{% if directory_argument_path %}
{% assign directory_to_inspect = directory_argument_path %}
{% else %}
{% assign directory_to_inspect = default_arg_directory_path %}
{% endif %}
{% if directory_argument_depth %}
{% assign directory_to_inspect_depth = directory_argument_path %}
{% else %}
{% assign directory_to_inspect_depth = default_arg_directory_depth %}
{% endif %}
{% comment %}
# Defaults read and assigned now to output results
{% endcomment %}
{{ directory_to_inspect_depth | replace:'/',' ' | truncatewords: directory_to_inspect_depth,"" | remove_first: '/' | replace:' ','/' }}
The above should output directory path lengths of whatever size desired and maybe included as shown previously or if feeling adventurous try what's shown below; though for looping and recursive features look to the linked script for how I've worked around stack size restrictions.
{% capture dir_sub_path %}{{include dir_path_by_numbers.html directory_argument_path="blog" directory_argument_depth=1}}{% endcapture %}
Note above is just speculation, untested, and maybe more buggy than scripts tested and hosted publicly... in other words inspiration.
Simplest way would be using
if page.url contains
example:
<li class="{% if page.url contains '/docs/' %}current{% endif %}">
Docs