Display YAML files in subfolders of collections in Jekyll - ruby

I've been banging my head against a wall trying to figure out how you do this. I have recently had to switch the way my _data folder works in Jekyll. Before it was:
_data
collection_1
file1.yml
file2.yml
file3.yml
collection_2
file1.yml
file2.yml
collection_3
file1.yml
From there Jekyll just did its thing and I had template files using Liquid and all was fine in the world.
Now my data structure is:
_data
collection_1
subfolder_1
file1.yml
file2.yml
subfolder_2
file1.yml
collection_2
subfolder_1
file1.yml
file2.yml
subfolder_2
file1.yml
collection_3
subfolder_1
file1.yml
Now I'm running into trouble. I have a liquid template where I'm trying to display all of the above info in a list. I can list out the names of the collections but I can't figure out how to then loop through the subfolders and extract their data and display it in the template. Here's my current template:
<div class="dropdown-content navbar-search-results">
<ul class="navbar-search-list">
{% for collection in site.data.company.[collections] %}
<h2 class="navbar-search-label-{{collection.label}}">{{ collection.label }}</h2>
<ul class="navbar-search-label-{{collection.label}}-list">
{% for subfolder in collection %}
<li>{{subfolder.name}}</li>
{% endfor %}
<li>hello list item</li>
</ul>
{% endfor %}
</ul>
</div>
Do I need another loop in the subfolder to grab the data from the YAML files in there? I tried that but it didn't work. In fact I've tried a lot of things and nothing! Anyone out there using Jekyll still and have any thoughts?

Related

Frontmatter automation and category sorting in Jekyll

I am new to Jekyll, and I am working on a site where I want to have a navigation menu that uses the category names as the link text. However, I don't want the cat names ordered alphabetically or reversed, but in a different order. The only thing I could come up with is, defining a hash in the config file like this:
cats:
"a": "dogs"
"b": "cats"
"c": "spiders"
"d": "jiraffes"
and then for the navigation I have something like this (please don't laugh at this noobie, he he):
<ul>{% for cat_hash in site.cats %}{% for cat in cat_hash %}{% for page in site.pages %}{% if cat[1] == page.category %}
<li>{{ page.category }}</li>{% endif %}{% endfor %}{% endfor %}{% endfor %}
</ul>
Now, since I have many pages under each category, I would like to automate the process a bit, so I'm trying to use liquid code in the front matter like this:
---
layout: default
category: {{ site.cats["a"] }}
---
but of course this doesn't work. I've searched SO and found a solution using a plugin, but I can not use plugins for this site. Anybody has any idea? What I would like to do is:
Have the categories sorted in any order I want, (not alphabetically).
Automate the cat name generation in the front matter
Thank you in advance.
A possible solution :
Ordering is not the problem and I think that the _config.yml seems to do it.
The problem is to automatically match a page to a category without having to write the category name in the pages's front matter.
My idea is then to match a category to a folder. Any file present in the cats folder will be considered to be part of the cats category, and then appear in the right menu.
--cats
|--cat1.md
|--cat2.md
|--
--dogs
|--dog1.md
|--dog2.md
|--
--spiders
|--spider1.md
Then the _config.yml can be changed a little to give a match between folder name and display in the menu.
categories:
dogs:
display: Doggies
cats:
display: I love catz
spiders:
display: Spiders
Now we can easily match our pages to a category and display everything in a menu :
{% for cat in site.categories %}
<h2>{{ cat[1].display }}</h2>
<ul>
{% for page in site.pages %}
{% if page.dir contains cat[0] %}
<li>{{ page.title }}</li></li>
{% endif %}
{% endfor %}
</ul>
{% endfor %}
Et voilà !

How to create sorted list of Pages in Octopress or Jekyll?

I have a Octopress website, which has posts and pages. Now I want to add another category of pages which I want to call as writepus ( notes which I will keep updating like a wiki via git commits).
I want to keep these notes in a folder called _notes, just like we have _posts in source folder of Octopress.
I have a folder called _writeups/ with files such as:
subject1.html
subject2.html
I have a file called notes/list.html with following content.
---
layout: page
navbar: Notes
title: Notes
footer: false
---
<div id="blog-archives">
{% for post in site.writeups reverse %}
{% capture this_year %}{{ post.date | date: "%Y" }}{% endcapture %}
{% unless year == this_year %}
{% assign year = this_year %}
<h2>{{ year }}</h2>
{% endunless %}
<article class="page-header">
{% include archive_post.html %}
</article>
{% endfor %}
</div>
Basically I want to create a listing of these writeups so that I can keep updating them as and when I get time. Also I want to keep these separate from posts and pages.
How can I achieve this functionality using Octopress / Jekyll ?
Jekyll version 2, which has only recently been released, has the ability to have extra collections and data. Collections is probably what you are looking for, so upgrade your version of Jekyll and visit http://jekyllrb.com/docs/collections/ to find out more about them.

Multiple Blogs In Single Jekyll Website

Is there a way I can have a single Jekyll website have more than one blog? I currently want to have two blogs in one site.
I am the author of the page http://www.garron.me/blog/multi-blog-site-jekyll.html
Considering that you need individual archives pages, and latest post per individual blog. Just use something like this:
Create a file archives-blog-1.html and fill it with:
{% for post in site.posts %}
{% if post.categories contains 'blog1' %}
<div class="post">
<h3 class="title">{{ post.title }}</h3>
<p class="meta">Date: {{ post.date }}</p>
</div>
{% endif %}
{% endfor %}
That will give you a list of all post in blog1, you can do the same for blog2. That page can be anyplace you want.
For the latest post, you can use the same code but enclosed between:
{% for post in site.posts limit:5 %}
....
{% endfor %}
That will give you the lastes 5 posts... I am using this
{% for post in site.posts limit:5 %}
<div class="post">
<ul>
<li>{{ post.title | truncate:200 }} <small>{{ post.date }}</small>
{% if post.summary %}
<p class="entry">{{ post.summary }}</p>
{% endif %}
</li>
</ul>
</div>
{% endfor %}
In my index page. http://www.garron.me/index.html ... under the sub-title (From the blogs)
I am not limiting to any category, so posts from all blogs appear there, you can limit with {% if post.categories contains 'blog1' %}
Hope it helps you.
There's a simpler solution than any of the answers so far.
Folder structure:
- blog1/
- _posts/
- blog2/
- _posts/
Then in the index.html for blog1, use site.categories.blog1 instead of site.posts.
See the documentation for "site.categories" and "page.categories" in https://jekyllrb.com/docs/variables/
I used two separate Jekyll installations to run two blogs on the same domain; if your blogs are going to live in separate root dirs (mine are at / and /photos/), then I'd recommend this approach. I also described how I merged both blogs' sitemap.xml files.
Your best bet would be to look into the data files feature. You can put .markdown files in a separate folder in your source and link to them as you post. This does mean that in order to make a post, you'll need to write a data file entry, but you can host as many "blogs" as you'd like, each with their own folder. Posts will automatically have the folder they're in as the url. I use this method for my own personal blog and portfolio.
Either that, or you may want to look into collections: http://jekyllrb.com/docs/collections/
Adding to #ggarron's answer, there's a short version of filtering by categories:
{% assign filtered_posts = site.posts | where_exp: "post", "post.categories contains 'blog1'" %}
The advantage of assigning to a variable is that one can replace all uses of site.posts with filtered_posts and keep consistency. For example, I have a snippet to get the first post of the list:
{% assign first_post = filtered_posts | first %}
This works as expected.

In Jekyll, site.posts returns nothing

I blog with Jekyll. In my source/index.html (I reconfigured the paths in _config.yml) I have written:
{{ site.posts }}
But when I compile it it gives no results. I am sure that I have posts, they are compiled and work as supposed.
I don't know where to start troubleshooting, have anyone else had such problem?
site.post returns and array of liquified Jekyll::Post objects. You can check the number of posts by simply writing:
{{ site.posts.size }}
and you could iterate through them writing:
<ul>
{% for post in site.posts %}
<li class="post">
<h1>{{ post.title }}</h1>
</li>
{% endfor %}
</ul>
In Jekyll posts need to be in the _posts folder to be included in the {{ site.posts }} variable.
There's a good chance that you may have simply omitted the underscore in your folder name.
Verify the post time, that it occurs in the past, future posts are not added to the site.posts.

An easy way to support tags in a jekyll blog

I am using the standard jekyll installation to maintain a blog, everything is going fine. Except I would really like to tag my posts.
I can tag a post using the YAML front matter, but how do I generate pages for each tag that can will list all posts for a tag?
Here is a solution with alphabetically sorted tags on a single page.
It uses Liquid only, which means that it works on GitHub Pages:
{% capture tags %}
{% for tag in site.tags %}
{{ tag[0] }}
{% endfor %}
{% endcapture %}
{% assign sortedtags = tags | split:' ' | sort %}
{% for tag in sortedtags %}
<h3 id="{{ tag }}">{{ tag }}</h3>
<ul>
{% for post in site.tags[tag] %}
<li>{{ post.title }}</li>
{% endfor %}
</ul>
{% endfor %}
You can see it in action here.
EDIT:
There's also a way to generate a separate page for each tag without plugins (which will work on GitHub Pages).
I have a more detailed explanation on my blog:
Separate pages per tag/category with Jekyll (without plugins)
First, you need a new layout file:
/_layouts/tagpage.html:
---
layout: default
---
<h1>{{ page.tag }}</h1>
<ul>
{% for post in site.tags[page.tag] %}
<li>
{{ post.date | date: "%B %d, %Y" }}: {{ post.title }}
</li>
{% endfor %}
</ul>
With this layout file, you can add a new tag page by adding a new file with just two lines of YAML front-matter.
Here's an example for the jekyll tag:
/tags/jekyll/index.html:
---
layout: tagpage
tag: jekyll
---
The only disadvantage of this approach: each time you use a new tag for the first time, you have to remember to create a new two-line file for it.
To generate the root index file (i.e. the list of tags that links to /tags/jekyll/index.html etc.), you can use a similar solution like the one on top of this answer where I generate a single page with alphebetically sorted tags:
{% capture tags %}
{% for tag in site.tags %}
{{ tag[0] }}
{% endfor %}
{% endcapture %}
{% assign sortedtags = tags | split:' ' | sort %}
{% for tag in sortedtags %}
{{ tag }}<br>
{% endfor %}
This will generate a list of links like this:
<ul>
<li>.net</li>
<li>authentication</li>
<li>backup</li>
</ul>
Note that this solution uses a blank to split tags, so it doesn't work when your tags contain blanks and Yevgeniy Brikman's comment applies here as well.
This gist will generate a page per category for you: https://gist.github.com/524748
It uses a Jekyll Generator plugin, plus a Page subclass.
Have a look at sites using jekyll. There are a few custom forks which have implemented tagging functionality, hopefully also in the way you want :-)
I had the same question, and stumbled upon this: http://gist.github.com/143571.
It's a rake task which generates a tag list. I modified it slightly, and my version is at:
http://github.com/mattfoster/mattfoster.github.com/blob/master/Rakefile.
Whilst this doesn't give you a page per tag, you can use anchors, which is half way there!
I use the great Jekyll Tagging plugin that automatically generates a tags cloud and tag pages. Easy to install and use.
Here is a page for the "photo" tag on my blog (in french), and you can see the tags cloud in the bottom.
Based on Christian's answer above I made a bash script that does what he described.
https://github.com/ObjectiveTruth/objectivetruth.github.io/blob/master/rebuild_tags.sh
Be sure to have the accompanying 14 line vim script in the /non_website_resources/ directory
AND
Make the /_layouts/tagpage.html shown in Christian's answer above but rename it to /_layouts/tag_pages.html
File structure should be like this:
.jekyll_website_root
├── _posts
├── _layout
│ ├── tag_pages.html
├── rebuild_tags.sh
Run from the root directory ./rebuild_tags.sh
If you get permission denied error be sure to run chmod 777 rebuild_tags.sh
If you look at scripts comments its fairly simple:
Uses sed to find all the tags in every .md file in _post directory
Uses sed to massage the data to proper format
Takes all the unique tags and makes a directory and a index.html for each
This way, if you have any new tags, just run the script to rebuild the pages before pushing to github
A nice simple non-plugin way to do tags
EDIT
Removed dependency on other files. Just need the one script!
I do these with CSS. First lists an element and use the tag name as its id.
<span id="{{ site.posts | map: 'tags' | uniq | join: '"></span><span id="' }}"></span>
And then lists all the post and use its tags as a value for the "tags" custom attribute.
{% for post in site.posts %}
<article class="post" tags="{% for tag in post.tags %}{{tag}}{% if forloop.last == false %}{{" "}}{% endif %}{% endfor %}">
<h3>{{post.title}}</h3>
</article>
{% endfor %}
And then in CSS, hide all the posts by default, and only show posts with tags matches the url id/ hash
.post {
display: none;
}
{% for tag in site.tags %}#{{tag[0]}}:target ~ [tags~={{tag[0]}}]{% if forloop.last == false %}, {% endif %}{% endfor %} {
display: block;
}
/*
The compiled version will look like this
#tagname:target ~ [tags~="tagname"], #tagname2:target ~ [tags~="tagname2"] {
display: block;
}
*/
I made an article about this here.

Resources