Jekyll how to write posts for different topics - jekyll

I am very new to jekyll. Currently, I noticed that there is only one /_posts folder in my project. All the posts I wrote in this folder will create a site in /_site/posts.
I wonder is there a way that I can write posts for different topics and generate the sites at different folders? For example, I want to write some posts related to 'travel', so I hope to put the markdown files in a folder like /_travel. I also want to write some posts related to 'work', so I hope to have a folder like /_work. And I hope jekyll can generate these websites separately, like /_site/travel and /_site/work.
The reason I want to solve this is I hope to create a path at the head of my posts. Currently, I am using
{% assign paths = page.url | split: '/' %}
{% for item in paths %}
{% if forloop.first %}
<span>
<a href="{{ '/' | relative_url }}">
{{ site.data.locales[site.lang].tabs.home | capitalize }}
</a>
</span>
{% elsif forloop.last %}
{% if page.collection == 'tabs' %}
<span>{{ site.data.locales[site.lang].tabs[item] | default: page.title }}</span>
{% else %}
<span>{{ page.title }}</span>
{% endif %}
{% elsif %}
<span>
<a href="{{ item | relative_url }}">
{{ site.data.locales[site.lang].tabs[item] | default: page.title }}
</a>
</span>
{% endif %}
{% endfor %}
But apparently, all my work and travel posts are located in the same folder _site/posts

First, you can create your own collections in _config.yml:
collections:
travel:
output: true
permalink: /:collection/:name
work:
output: true
permalink: /:collection/:name
output: true will render a page for each document in the collection.
Then you can create two folders named _travel and _work where you can put your posts.
You access the content of posts in each folder like this:
{% for travel_post in site.travel %}
...
<p>{{ travel_post.content }}</p>
...
{% endfor %}
Lastly, permalink: /:collection/:name should create a link at /travel/name_of_post. See Permalinks for collections for a list of placeholders for the permalink configuration variable.

Related

How to avoid duplicate pages with collections using jekyll paginate v2?

I followed the approach to install paginate v2 and paginate a collection, but I get an additional "Example Collection" top level page link for every page created by paginator.
Here is example.md
---
layout: page
title: Example Collection
permalink: /example/
pagination:
enabled: true
---
{% for post in paginator.posts %}
<h1>{{ post.title }}</h1>
{% endfor %}
{% if paginator.total_pages > 1 %}
<ul>
{% if paginator.previous_page %}
<li>
Newer
</li>
{% endif %}
{% if paginator.next_page %}
<li>
Older
</li>
{% endif %}
</ul>
{% endif %}
And this is what I added to my config.yml
# Collections
collections:
examplecol:
output: true
permalink: /:collection/:path/
# Plugin: Pagination (jekyll-paginate-v2)
pagination:
collection : 'examplecol'
enabled : true
debug : false
per_page : 3
#permalink : "/page/:num/"
title : ":title - Page :num of :max"
limit : 0
sort_field : "date"
sort_reverse : true
Now, if there are more than 3 files in the _examplecol folder, I get more than 1 instance of the example.md as a page in my header.
How can I have just one instance of Example Collection in the header that holds all of the paginated pages? I think I'm missing something silly.
I tried deleting the permalink entry in the example.md YAML, but that just made it so that the jekyll processor could not find examplecol/index.html.
It took me a lot of trial and error, but I found the solution in the header.
When the paginator makes pages with some items, the site sees them as pages and renders them.
Therefore, the site finds all the true responses to my_page.title and creates page-links.
<div class="trigger">
{% for my_page in site.pages %}
{% if my_page.title %}
<a class="page-link" href="{{ my_page.url | relative_url }}">{{ my_page.title | escape }}</a>
{% endif %}
{% endfor %}
</div>
Since the paginator pages are autogen, you can filter them out:
<div class="trigger">
{% for my_page in site.pages %}
{% if my_page.title and my_page.autogen == nil %}
<a class="page-link" href="{{ my_page.url | relative_url }}">{{ my_page.title | escape }}</a>
{% endif %}
{% endfor %}
</div>

Output link to "parent page"?

I have a collection _colletion. In there is a file _collection/path/topic.md and a folder _collection/path/topic/ that includes lots of .md files with content. The permalinks for these files are /path/topic and /path/topic/file-x - so a parent page with a folder with the same name with multiple random pages in it.
Now I want to output a link to /path/topic in all these .md files with the title of topic.md as link text:
---
title: This is the page title defined in topic.md
---
should become
This is the page title defined in topic.md
How do I do that most easily?
Can I somehow access the folder name topic of the .md files and use this to read topic.md and output it's title and also generate a link to it?
My current manual "solution" (or workaround):
Add a parent entry to the frontmatter of all pages in /topic/ that contains the title and relative URL for the topic.md:
parent: ['Topic Title', '../topic']
In the template of the pages:
{% if page.parent %}
<p>« {{ page.parent[0] }}</p>
{% endif %}
Works, but of course duplicates this information n times and has to be maintained manually.
How about this (option 1)?
{% assign pageurl_array = page.url | split: "/" %}
{% assign path = pageurl_array[0] %}
{% assign topic = pageurl_array[1] %}
<p>« <a href="{{ path }}/{{ topic }}/{{ topic }}.html">
{{ topic | capitalize | replace: "-", " " }}
</a></p>
If you do not mind crazy build times, do this (option 2):
{% assign pageurl_array = page.url | split: "/" %}
{% assign path = pageurl_array[0] %}
{% assign topic = pageurl_array[1] %}
{% capture parent_url %}{{ path }}/{{ topic }}/{{ topic }}.html{% endcapture %}
<p>« <a href="{{ parent_url }}">
{% for i in site.pages %}
{% if i.url == parent_url %}
{{ i.title }}
{% endif %}
{% endfor %}
</a></p>
I would go for the first option (much faster) and use this javascript to get the capitals and special characters right:
$('a').each( function() {
var str = $(this).html();
str = str.replace('Topic from url', 'Topic from URL');
$(this).html(str);
});
I admit that the javascript solution is far from pretty, but it solves the build time problem pretty well.
Note that Jekyll is pretty slow. I would advice you to dig into Hugo if you require faster build times.
During discussion in the comments on my question and the other answers I noticed that what I wanted to build was actually a very common thing: A breadcrumb navigation! Just a very "small" one, with only one level.
With this newfound knowledge I could google "breadcrumb" plugins for Jekyll:
This solution uses the path of the page to extract the "crumbs":
https://www.mikestowe.com/blog/2017/08/adding-breadcrumbs-in-jekyll.php
It uses the folder name for the link text.
Another similar implementation:
https://stackoverflow.com/a/9633517/252627
Another one:
https://stackoverflow.com/a/37448941/252627
So no title link text in all of these.
This solution actually reads the page title, but can also read breadcrumb frontmatter from the pages, and uses these as link text:
https://github.com/comsysto/jekyll-breadcrumb-for-github-pages/
https://comsysto.com/blog-post/automatic-breadcrumb-for-jekyll-on-github-pages
https://gist.github.com/csgruenebe/8f7beef9858c1b8625d6
This one might be a valid solution.
There are also real plugins (that unfortunately don't work with Github Pages):
https://github.com/git-no/jekyll-breadcrumbs
My solution, based on JoostS code:
{% assign url = page.url | remove:'.html' | split: "/" %}
{% assign path = url | pop %}
{% if path.size == 1 %}
<a class="back" href="/home/">home</a>
{% else %}
<a class="back" href="/{% for dir in path offset: 1 %}{{ dir | append: "/" }}{% endfor %}">{{ path | last }}</a>
{% endif %}```

Find post where key has specific value in Jekyll

I need to be able to compare a value in each of the markdown files in a folder called in_media to the user_id of the current page stored in a _users folder and only display the post title that have that value from the in_media folder.
User markdown file in _users folder
---
user_id: 123
title: bob
---
Post markdown from in_media folder
---
users: 123
---
I tried the following:
{% for this_user in site.in_media %}
{% for user in page.user %}
{% if this_user == user.user_id %}
<li><a href="{{ post.external_link }}">{{ post.title }}</a </li>
{% endif %}
{% endfor %}
{% endfor %}
However, this is not returning anything
Try this way:
{% for post in site.in_media %}
{% if post.value == page.title %}
<li>{{ post.title }}</li>
{% endfor %}
{% endfor %}
I'm not sure that you can use external_link, never heard of it. Maybe you'll need to build permalink manually - depending on your _config.xml.
Also note the collection should be properly set up to work with permalinks.

Include a file, but only if it exists?

I'm creating a style guide in Jekyll and using Collections to define different elements of the guide. For example, headings, lists, etc.
I'm trying to separate the Sass into files that match up with the partials, one to one, and I'd like to render the Sass files as part of each collection.
So, something like:
{% if _includes/_sass/{{ entry.title | append: ".scss"}} %}
{% highlight sass %}
{% include _includes/_sass/{{ entry.title | append: ".scss" }} %}
{% endhighlight %}
{% endif %}
Basically, what I want is "Include a file in this directory that has the same name as this entry in my collection. If it doesn't exist, don't break."
How do I do this? I've explored storing the file path in a variable but can't seem to get that to work.
Thanks in advance.
It can be done.
This works on Jekyll 3 but it can certainly be ported to Jekyll 2.
Starting from a base install (jekyll new)
_config.yml
collections:
guide:
sasssamples:
Style guide files
Our samples will be grouped in the _guide collection.
Example file : _guide/header/header1.hmtl
---
title: Header level 1
---
<h1>Header level 1</h1>
SCSS samples
We want our SCSS samples to be included in our css/main.scss and use variables defined in our other SCSS files. Our samples will be integrated at the end of our css/main.scss
We don't want our SCSS samples to render as css so no .scss extension. Switch to .txt extension
We want to access SCSS samples from a list. Let's put them in a sasssamples collection.
Example file : _sasssamples/header/header1.txt
---
---
h1{
color: $brand-color;
border: 1px solid $brand-color;
}
SCSS samples integration
Add this code at the very end of you bootstraping scss file (css/main.scss on a base Jekyll install)
css/main.scss
[ original code ... ]
{% comment %} Selecting a collection the Jekyll 3 way. See https://github.com/jekyll/jekyll/issues/4392 {% endcomment %}
{% assign scssCollection = site.collections | where: 'label', 'sasssamples' | first %}
{% comment %}
Printing documents in sasssamples collection.
All SCSS from style guide are sandboxed in .guide class
This allows us to apply styles only to style guide html samples
{% endcomment %}
.guide{
{% for doc in scssCollection.docs %}
{{ doc.content }}
{% endfor %}
}
The style guide
<h2>Style guide</h2>
{% comment %}Selecting a collection the Jekyll 3 way. See https://github.com/jekyll/jekyll/issues/4392 {% endcomment %}
{% assign guideCollection = site.collections | where: 'label', 'guide' | first %}
{% assign scssCollection = site.collections | where: 'label', 'sasssamples' | first %}
{% comment %} Looping hover style guide samples {% endcomment %}
{% assign samples = guideCollection.docs %}
{% for sample in samples %}
<article>
<h3>Element : {{ sample.title }}</h3>
<h4>Render</h4>
<div class="guide">
{{ sample.content }}
</div>
<h4>html code</h4>
{% highlight html %}{{ sample.content }}{% endhighlight %}
{% comment %}
Changing a path like : _guide/headers/header1.html
to : _sasssamples/headers/header1.txt
{% endcomment %}
{% assign scssPath = sample.path | replace: '_guide', '_sasssamples' %}
{% assign scssPath = scssPath | replace: '.html', '.txt' %}
{% comment %} Try to find a SCSS sample with equivalent path {% endcomment %}
{% assign scssSample = scssCollection.docs | where: 'path', scssPath | first %}
{% comment %}We print SCSS sample only if we found an equivalent path{% endcomment %}
{% if scssSample != nil %}
<h4>SCSS code</h4>
{% highlight css %}{{ scssSample.content }}{% endhighlight %}
{% endif %}
</article>
{% endfor %}
Done!
Seems it only miss on assigning the correct path
{% if _includes/_sass/{{ entry.title | append: ".scss"}}
Need to be replaced to relative path to the scss file:
{% assign scssPath = 'relative/path/to/your/scss/' %}
{% if {{ entry.title | append: ".scss" | prepend: scssPath }} != nil %}

Accessing posts via directory tree in Jekyll

Let's say I have a directory like the following:
|things
|---|animals
|---|---|dog
|---|---|cat
|---|---|other
|---|languages
|---|---|Afrikaans
|---|---|Latin
|---|---|Japanese
|---|---|other
and I want to access all of the posts under the "other" category that is under the "languages" category.
I want to be able to do
{% for post in site.categories.things.languages.other do %}
but that apparently doesn't work in Jekyll.
If I can avoid it, I'd like to not do
{% for post in site.categories.cobol do %}
{% if post.categories equals ["things", "languages", "other"] %}
but if I absolutely must, I will.
If you want to simply output a list of posts contained in a given path :
languages_other.html
---
path: "things/languages/other/"
---
{% include post_by_folder.html path=page.path %}
_includes/posts_by_folder.html
<h1>Posts in folder {{ include.path }}</h1>
<ul>
{% for post in site.posts %}
{% if post.path contains include.path %}
<li>
{{ post.title }}
</li>
{%endif %}
{% endfor %}
</ul>
Now any time you want to make a list of posts in a particular folder, you just have to create a page like languages_other.html.