How does Jekyll treat posts in _posts/subdir - jekyll

The Jekyll Bootstrap project has a sample blog post in the directory _posts/core-samples/ .
I assume, posts (files) in sub directories are handled the same way as posts in the root directory. Is this correct?
If so, I will add a "stage" sub directory, exclude it, so I can park posts and publish them by moving them.

Accidentally found it in the post - yaml section:
Instead of placing posts inside of folders, you can specify one or
more categories that the post belongs to. When the site is generated
the post will act as though it had been set with these categories
normally. Categories (plural key) can be specified as a YAML list or a
space-separated string.
So sub directories == categories

As the different is only on post.path so I would agree to your statement:
posts(files) in sub directores are handled the same way as posts in
the root diretory
You can park your posts in the directory _posts/core-samples/ and publish them like this:
{% for post in site.posts %}
{% if post.path contains 'core-samples' %}
..your code
{% endif %}
{% endfor %}
As a working sample you may see how this code publish these parked posts in their section.

I ended up here because I wanted to create the following structure:
index.html
_animals
cats
my-cat.html
...
dogs
my-dog.html
...
I created that structure, then in _config.yml:
collections:
animals:
output: true
permalink: /animal/:title.html
Finally, to get just the dogs in index.html:
<div id='dogs'>
{% for a in site.animals %}
{% if a.path contains 'dogs' %}
<a href='{{ a.url }}'>{{ a.title }}</a>
{% endif %}
{% endfor %}
</div>
NB: that this approach requires that the directory containing all the records (_animals in my example) can't be named _posts, as the latter is a special name in Jekyll.

Actually what that statement says is to put _posts folder inside a sub directory.
And then that sub directory will be treated as category.

Related

Is it possible to loop over subfolders in Jekyll?

I'm currently trying to loop over a subfolder in Jekyll but I don't know whether this is possible.
My folder structure looks like this:
_includes
_layouts
_pages
folder_1
folder_2
index.html
For example, I want to reach folder_1 by a loop how can I do this?
{% for page in pages.folder_1 %}
//xyz
{% endfor %}
What I want is that I've a static page and on this page I want to display the title and the description of each page in one of the subfolders.
Could you please help me?
Avoid naming main folder with an underscore unless you are using the _posts folder.
Then filter posts or pages checking their path:
{% assign folder1 = site.pages | where_exp: "item" , "item.path contains 'folder1'"%}
{% for item in folder1 %}
{{item.title}}
{% endfor %}

How can I sort posts by tags in Jekyll?

I'm not familiar with Ruby and I know there's a common Jekyll plugin for doing this but I tried all day and have not been able to get it working.
I added this plugin:
module Jekyll
class TagIndex < Page
def initialize(site, base, dir, tag)
#site = site
#base = base
#dir = dir
#name = 'index.html'
self.process(#name)
self.read_yaml(File.join(base, '_layouts'), 'tag_index.html')
self.data['tag'] = tag
tag_title_prefix = site.config['tag_title_prefix'] || 'Posts Tagged “'
tag_title_suffix = site.config['tag_title_suffix'] || '”'
self.data['title'] = "#{tag_title_prefix}#{tag}#{tag_title_suffix}"
end
end
class TagGenerator < Generator
safe true
def generate(site)
if site.layouts.key? 'tag_index'
dir = site.config['tag_dir'] || 'tag/tag'
site.tags.keys.each do |tag|
write_tag_index(site, File.join(dir, tag), tag)
end
end
end
def write_tag_index(site, dir, tag)
index = TagIndex.new(site, site.source, dir, tag)
index.render(site.layouts, site.site_payload)
index.write(site.dest)
site.pages << index
end
end
end
and to _config.yml I added
tag_dir: /tag
I display the list of tags with this include file:
<div class="tags modal">
<ul>
{% for tag in site.tags %}
<li>
<a href="/tag/{{ tag | first | slugize }}/">
{{ tag | first }}
</a>
</li>
{% endfor %}
</ul>
</div>
And when I try to select a tag, the url changes appropriately but nothing else changes. It does not display my tag_index template or filter the tags.
The site can be previewed and full source is available here. I've been banging my head against the wall for a while and can't for the damned of me figure out what I'm not doing right.
If one single tag page with all posts for all tags (like this one on my blog) is enough for you, you can just generate it with Jekyll/Liquid, without using any plugins at all.
If you absolutely want a separate page for each tag, then you have only two choices:
David Jacquel's answer (generate the page with the plugin on your local machine and push only the generated HTML to GitHub)
Each time you're writing a post where you use a new tag for the first time, manually create a new page with the tag name where you load all posts for that tag
Both choices are a bit more work than the tag page from my blog (see the first link), but there's no other way when you want one page per tag on GitHub Pages.
Only some plugins are supported by github pages. Your tag pages are not currently generated.
If you want to use your tag plugin, you have to
generate you site locally
add an empty .nojekyll file
push the generated files in you master branch
you can also push you code in an other branch like code
If you can't solve the trouble of sorting your posts by tags, you may consider
collections.
Collections in Jekyll is a set of items which has a certain relation between individual items but may not have a chronological arrangement.
For example, let’s consider you have a blog which is about movie reviews. You write your reviews as posts. So for every movie you create a post. Let’s say you want to make a list of Top 25 must watch movies or Top 10 scary movies which will have all the details of each movie.
In this case, posts or pages are not a good choice to go with. Use collections instead.
You can have any number of collections. It is a collection of certain kind of things. A collection of fruits, a collection of veggies, collections of beverages etc. Do not create collections for subsets, for example, say exotic fruits. They come under the fruit collection. In such cases use categories.
Maybe things have changed since this was posted, but sorting via tags (or categories) is built into Jekyll. You can do this by using the proposed method in the docs on Jekyll's website.
From the site:
Jekyll makes the categories available to us at site.categories. Iterating over site.categories on a page gives us another array with two items, the first item is the name of the category and the second item is an array of posts in that category... For tags it’s exactly the same except the variable is site.tags.
{% for tag in site.tags %}
<h3>{{ tag[0] }}</h3>
<ul>
{% for post in tag[1] %}
<li>{{ post.title }}</li>
{% endfor %}
</ul>
{% endfor %}
That ☝️ will give you each tag and its associated posts of your Jekyll site. You could go a step further and only return a specific tag(s). For example only list the tag nsfw and its associated posts.
{% for tag in site.tags %}
{%- if tag[0] == "nsfw" -%}
<h3>{{ tag[0] }}</h3>
<ul>
{% for post in tag[1] %}
<li>{{ post.title }}</li>
{% endfor %}
</ul>
{%- endif -%}
{% endfor %}

Jekyll Docs folder

Im my Jekyll website I need to create an documentation section similar to Original website. However I am not sure how the Docs sections renders. For example, the docs folder, which is located in site root, is filled with documentation .md files. This folder doesn't inculde any index.html file responsible for Layouting of website. The link to that folder is
Doc<span class="show-on-mobiles">s</span><span class="hide-on-mobiles">Documentation</span>
Could someone shed a light on how this section is rendering?
The docs folder includes an index.md, which is rendered as index.html in the final site.
If you look at the YAML front matter of index.md, you'll see this:
---
layout: docs
title: Welcome
next_section: quickstart
permalink: /docs/home/
---
The permalink: /docs/home/ line sets the final URL to {{ site.url }}/docs/home/, even though the actual file is in the /docs folder and the /docs/home folder doesn't even exist.
(for more info about the permalink setting, see Predefined Global Variables in the docs)
So that's where the URL comes from.
Concerning the list of documentation topics (the sidebar on the right):
The YAML front matter of index.md (see above), also contains the line layout: docs.
This refers to /_layouts/docs.html, a layout file.
Inside the layout file, there's the line {% include docs_contents.html %}, which refers to _includes/docs_contents.html, an include file, which contains the following code:
{% for section in site.data.docs %}
<h4>{{ section.title }}</h4>
{% include docs_ul.html items=section.docs %}
{% endfor %}
site.data.docs (in the first line) refers to /_data/docs.yml, a YAML data file.
It looks like this (shortened):
- title: Getting Started
docs:
- home
- quickstart
- installation
- usage
- structure
- configuration
- title: Your Content
docs:
- frontmatter
- posts
- drafts
- pages
- variables
- datafiles
- assets
- migrations
The code inside docs_contents.html loops through the items in the data file, displays the title values ("Getting Started", "Your Content"...) and then includes another include file /_includes/docs_ul.html, passing the list of docs from the data file.
This second include file loops through the list of docs, and does the following for each one:
Step 1:
{% assign item_url = item | prepend:'/docs/' | append:'/' %}
This builds the URL of the page based on the list item. For example, quickstart becomes /docs/quickstart/.
Step 2:
{% if item_url == page.url %}
{% assign c = 'current' %}
{% else %}
{% assign c = '' %}
{% endif %}
This marks the current page (used in the next step) by checking if the URL created in the previous step is equal to the URL of the current page.
Step 3:
{% for p in site.pages %}
{% if p.url == item_url %}
<li class="{{ c }}">{{ p.title }}</li>
{% endif %}
{% endfor %}
This loops all pages in the whole site, until it finds the page with the URL created in the first step.
(to make sure that the URL is equal, all Markdown files in the docs folder have set a permalink in the front-matter, for example permalink: /docs/quickstart/ in quickstart.md)
Then, it outputs a <li> with a link to the page, using the title from the respective Markdown file as the link text.
Plus, the class of the <li> is set to current if it's the current page (see step 2), so the current pae is highlighted in the list:

Jekyll not generating pages in subfolders

I use GitHub Pages and created some pages in a sub folder. It seems to be not generating pages I created in sub folder. All other pages work fine. The directory structure is like this:
/
/index.html
/_config.yaml
/_includes
/_layouts
/_posts
/tag
/tag/personal.html
/tag/videos.html
The pages inside the /tag directory are not generated by Jekyll. Also, usually GitHub sends an email if Jekyll build fails, but did not, in this case. Also, if I do any other changes it works, so the build is apparently not failing.
The /tag/personal.html is here:
---
layout: default
title: Tag-personal
permalink: /tag/personal/index.html
tagspec: personal
---
<div id="tagpage">
<h1>Posts tagged personal</h1>
{% include tags.html %}
</div>
and /_includes/tags.html is here:
{% for tag in post.tags %}
{% if tag == page.tagspec %}
{% assign ispostviable = true %}
{% endif %}
{% endfor %}
<ul class="posts">
{% for post in site.posts %}
{% if ispostviable == true %}
<li><a href="{{ post.url }}"></li>
{% endif %}
{% endfor %}
</ul>
PS: I use GitHub Pages and have no access to a Jekyll instance at my development machine (Windows).
Joshua Powell provided step-by-step directions in reply to a similar question on Github.
Edit _config.yml to add the following line (or expand the array, if it exists)
include: ['_pages']
where _pages is the name of the folder in which you wish to keep your files. (This also works for nested folders if you explicitly add them, e.g., ['_pages', '_pages/foo'].)
Move your pages into that folder. (These pages may be HTML, Markdown, or whatever else Jekyll renders when it’s placed in the root folder.)
Give them front matter with an appropiate permalink including a trailing slash, e.g., permalink: "/about/".
I found the culprit. It was that In Jekyll v1.0, absolute permalinks for pages in subdirectories were introduced. Until v1.1, it is opt-in. Starting with v1.1, however, absolute permalinks became opt-out, meaning Jekyll defaults to using absolute permalinks instead of relative permalinks.
The pages were being generated at /tag/tag/personal.html and so on.
There were two solutions:
Specify relative_permalinks: false in _config.yaml
Make permalinks relative to the subdirectory.
I chose the first option.

Generating a list of pages (not posts) in a given category

I am using Jekyll as a static generator for a website (not a blog), and I want to have an automatically generated list of all pages on my index page. Specifically, I want to have different categories and list all articles in each category separately. Here's an example of what I'm describing, if you're having trouble following. Is there any way to do this in Jekyll (e.g. GitHub pages)? I've seen the variables documentation page but that seems specific to the blog post format.
While building my own site I came across this very same problem, and I have found an (IMHO) easy and robust solution.
The Problem
Given a subset of pages (not posts) on the site, list them under headings based on their categories. For example: given a set of pages which we consider resource pages (or reference pages, or whatever logical grouping of pages that you want to display are), we want to list them under their categories (ex. code, explanation, et cetera).
The Solution
To get the behaviour that we want, we have to make modifications in three places:
_config.yml
resources.md
resource-file-X.md
_config.yml
In _config.yml, we must add a list of all of the categories/keywords/tags (or whatever you want to call it) that will appear in the resource files. Here is what I have in mine:
category-list: [code, editors, math, unix]
You can call the variable anything, I chose category-list, just make sure that you use the same variable in the resource.md file.
Note: The order that you place the items in the list is the order they will be listed on the resource.md page.
resource-file-X.md
These are the files that you want to have indexed and linked to on the resources.md page. All that you need to do is add two file variables to the top of each of these files. The first is to indicate that this file is a resource file.
resource: true
The second is to indicate what categories you want this file to be indexed under. You can index it under as many categories as you would like, and if you want a page un-indexed, leave the list blank. My reference for proper EINTR handling in C has the following categories:
categories: [code, unix]
resources.md
This is the file that will generate the list of pages based on their respective categories. All you need to do is add the following code to this file (or whatever file you want the list to be on):
{% for cat in site.category-list %}
### {{ cat }}
<ul>
{% for page in site.pages %}
{% if page.resource == true %}
{% for pc in page.categories %}
{% if pc == cat %}
<li>{{ page.title }}</li>
{% endif %} <!-- cat-match-p -->
{% endfor %} <!-- page-category -->
{% endif %} <!-- resource-p -->
{% endfor %} <!-- page -->
</ul>
{% endfor %} <!-- cat -->
Code Breakdown
Just a quick explanation of how this works:
Loop through each of the categories specified in _config.yml.
Display a heading with that category name.
Start an unordered list for the pages that belong in that category.
Loop through the pages on the site.
If the page is a resource file as indicated by the file variable resource, then for each of the categories that the file belongs to, if one of them matches the current category being listed, display a link to that page.
Note: the variables category-list in _config.yml and categories in the resource files can be called whatever you want, just make sure that you use the same variables in the file generating the list.
Another Note: When you modify _config.yml, you have to completely restart Jekyll, even if you have the --watch option, you have to stop and restart it. It took me a while to figure out why my changes weren't taking effect!
The Final Product
You can see the final product on the resources page on my site, although I just put this together today so at the time of this writing, it's far from complete, but you can check out my bio if you want on the home page.
There's a cleaner way to do this using the liquid "contains" property:
In _config.yml, add your index of categories
categories: [fruit, meat, vegetable, cheese, drink]
In your page.md inside the front matter, add one or more of the categories available in the _config.yml
---
layout: page
title: Orange juice
description: Orange juice is juice from oranges. It's made by squeezing oranges.
categories: [fruit, drink]
---
In your template to get all the pages in the fruit category you do:
{% for page in site.pages %}
{% if page.categories contains 'fruit' %}
<div class="item">
<h3>{{page.title}}</h3>
<p>{{page.description}}</p>
</div>
{% endif %}
{% endfor %}
You should differentiate between pages and posts (articles). Listing all posts sorted by category is not a problem at all. You can loop through site.categories. It contains the category name and a list of all posts in that category.
Listing all pages is possible, too. You can loop through site.pages. But a page does not belong to a specific category (only posts do).
When I take a look at your posted example, using categories on posts and then looping through site.categories seems to be the way to go. It will get you exactly the desired output.
There are some variations/ simplifications possible (answer of felipesk). Maybe due to improvements in Jekyll.
There is NO index needed in _config.yml.
If the list of pages are not listed in a page but for example in a doc, you can add the category also to the doc:
---
layout: doc
title: Fruit List
categories: [fruit]
---
And then use it like this:
{% for p in site.pages %}
{% if p.categories contains page.category %}
* [{{ p.title }}]({{ p.url | absolute_url }})
<small>{{ p.excerpt }}</small>
{% endif %}
{% endfor %}
With posts this can even be shorter:
{% for post in site.categories[page.category] %}
* [{{ post.title }}]({{ post.url | absolute_url }})
<small>{{ post.excerpt }}</small>
{% endfor %}
Why this only works for posts, I could not figure out yet.
The interesting point is that this snippet can be used everywhere (if you mix docs/pages/posts)!
So just add it as an _includes and use it like:
## Further Reading
{% include pages-list.md %}
I work with the theme Minimal Mistakes