Multi-Row Blog List in Jekyll

Multi-row blog list in Jekyll

These are actually two questions.

Number one: How to display two posts in each row with Jekyll/Liquid?

I answered two similar questions yesterday:

  • For loop, wrap every two posts in a div

    (one solution for a fixed number of posts - like the last 10 posts in groups of two on the front page - and one solution for an infinite number of posts)
  • Jekyll automatically processing rows

    (another solution with an infinite number of posts, but with four posts per group and with a detailed step-by-step explanation)

Number two: How to achieve a design similar to the one in your screenshot in Bootstrap?

Bootstrap has a page with example designs that you can steal. Especially these two:

  • Jumbotron
  • Narrow jumbotron

Look at the source code of the example pages - basically, you just have to wrap the posts in a few <div>s with the right classes.

For example, this is the source code for the three blocks in the Jumbotron example

<div class="row">
<div class="col-md-4">
<h2>Heading</h2>
<p>blah</p>
</div>
<div class="col-md-4">
<h2>Heading</h2>
<p>blah</p>
</div>
<div class="col-md-4">
<h2>Heading</h2>
<p>blah</p>
</div>
</div>

You just need to modify the code examples from my other answers (linked above) so that they generate a similar combination of <div>s.

Plus, you may want to read about Bootstrap's grid system to get the columns right (e.g. the class col-md-4 in the example code above varies depending on the number of columns you want).


Finally, a real-world example: My blog has a similar listing on the front page.

This is a fixed number of posts (the last nine, three rows of three), so I'm using the first approach from this answer.

The source code of the front page is here.

Note that I'm still on Bootstrap 2 (not 3), so you can't just copy and paste the CSS classes from my source code!

Two Columns - One Ordered List Jekyll

Here's an idea: Use one column and add style="column-count: 2" to that. Done!

More css column options: https://css-tricks.com/almanac/properties/c/columns/#article-header-id-0

Creating two blogs on same website (Jekyll GitHub) without altering layout/formatting

You've removed the posts collection from your _config.yml which was setting the default feature_image for all posts. Unless you add that back in or include the overrides in each individual post it will not display the header (it may or may not also affect the rest of the styles):

collections:
media:
title: Media # Needed for Siteleaf
output: true
description: "Recent discussions with the media." # The post list page content
feature_text: |
Sharing our motivations and
opinions with the media.
feature_image: "https://picsum.photos/2560/600?image=866"

You're not actually using a media collection in either blog/index.html nor media/index.html, you're using the post.categories for filtering in the end, which will still causes some weird pagination once you start getting things rolling.

You may want to look at using the separate collections and then pre-building your site using paginator v2 (https://github.com/sverrirs/jekyll-paginate-v2/blob/master/README-GENERATOR.md) which will allow for pagination of different collections.

Edit 2020-01-23

Taking a new look at your repository, you still only have one (posts) collection. Therefore the logic for reading feature_* is being shared. If you look at the include site_feature.html you can see how the feature_image is being parsed out of the collections.

{% assign collectiondata = site.collections | where: "label", page.collectionpage | first %}

Which in your case is why Blog and Media both have the second image ?image=213. Your blog.html and media.html still have the front matter collectionpage: post.

I still think you're going down a slippery slope which will result in things not working exactly as you want them once you get more and more posts by doing it this way.

Jekyll every 4th item in loop display differently

I think you can just walk through your items while checking the modulo. Like this:

<div class="row blogitems">
{% for post in site.posts %}
{% assign mod3 = forloop.index | modulo: 3 %}
<div class="col-md-6"><p>{{ post.title }}</p></div>
{% if mod3 == 0 %}<div class="col-md-6"><p>THIS IS NOT A POST</p>{% endif %}
{% if mod3 == 0 or mod3 == 2 %}</div><div class="row blogitems">{% endif %}
{% endfor %}
</div>

How can I have multiple authors for one post in Jekyll?

If you want to specify multiple authors in your YAML Frontmatter, then you are going to want to use YAML's list syntax like you did with categories and tags, like this:

author:
- usman
- someone_else

This will be useful for dynamically injecting author information into each of the posts.

As for allowing multiple people to contribute to the same article, I don't think this has anything to do with Jekyll or what is specified in the Frontmatter. This is an issue of having your Jekyll content hosted in a shared place (such as on GitHub, like many do) where both you and your collaborator can both work on the file. That being said, be aware that you may run into nasty merge conflicts if you work on that same markdown file in parallel.

Update

This is an update based on the OP's edits to the original question.

A simple hacked approach would be to set your author tag like this:

author: Usman and Someone_Else

This doesn't give you much flexibility though. A better solution, which would require you to modify the template you are using, would be to do something like the following:

First, setup your YAML Front Matter so that it can support multiple authors.

authors:
- Usman
- Someone_else

Now, you modify the template to go through the authors specified in the YAML Front Matter.

<p>
{% assign authorCount = page.authors | size %}
{% if authorCount == 0 %}
No author
{% elsif authorCount == 1 %}
{{ page.authors | first }}
{% else %}
{% for author in page.authors %}
{% if forloop.first %}
{{ author }}
{% elsif forloop.last %}
and {{ author }}
{% else %}
, {{ author }}
{% endif %}
{% endfor %}
{% endif %}
</p>

Resulting HTML:

If no authors are specified:

<p>No author</p>

If one author is specified:

<p>Usman</p>

If two authors are specified:

<p>Usman and Someone_Else</p>

If more than two authors are specified:

<p>Usman, Bob, and Someone_Else</p>

For loop, wrap every two posts in a div

I know I'm late to the game but I found what I feel is a fairly elegant solution that doesn't feel hacky.

With for loop's limit and offset params, we can iterate one row at a time, N posts per row.

First, we count the number of rows we'll need to enumerate over:

{% assign rows = site.posts.size | divided_by: 2.0 | ceil %}

The Ruby equivalent would be rows = (posts.size / 2.0).ceil (odd numbers get their own row).

Next, we'll iterate over the rows:

{% for i in (1..rows) %}
<div>

Now we need to calculate the collection offset with (i - 1) * 2 (using forloop.index0):

  {% assign offset = forloop.index0 | times: 2 %}

Then we can iterate over the slice of posts starting at the row's offset (equivalent to posts[offset, 2] in Ruby):

    {% for post in site.posts limit:2 offset:offset %}
<a href="{{ post.url }}">{{ post.title }}</a>
{% endfor %}

Close the row div element and for loop:

  </div>
{% endfor %}

That's it!

In Ruby, this would be:

rows = (posts.size / 2.0).ceil # the number of rows
(1..rows).each do |i|
offset = (i - 1) * 2
# <div>
posts[offset, 2].each do |post|
# <a href="#{post.url}>#{post.title}</a>
end
# </div>
end

All together now, in Liquid:

{% assign rows = site.posts.size | divided_by: 2.0 | ceil %}
{% for i in (1..rows) %}
{% assign offset = forloop.index0 | times: 2 %}
<div>
{% for post in site.posts limit:2 offset:offset %}
<a href="{{ post.url }}">{{ post.title }}</a>
{% endfor %}
</div>
{% endfor %}

Hope this helps someone!

Jekyll multiple custom repeatable content

I figured out the problem. First one is the folder structure. Simply keep all the postfiles in the _posts/ file in the root directory. The second one is the capitalization of the category name in your liquid tag. Although there are no semantic differences between JOBS and jobs, when used in liquid arguments, they act in a weird way. So try to keep them in lower case. Simply replace the line

{% for post in site.categories.JOBS %}

with this

{% for post in site.categories.jobs %}

This won't solve your problem right away. Jekyll expects you to wrap your posts YAML matter between --- 3 dashes. So you've to use the following format for you post markdown and everything will work:

---
title: test
category: jobs
length: April 2010 – April 2012
position: Junior Developer
---
Content to be displayed

Jekyll automatically processing rows

Note:

I couldn't get the sorted_for plugin to work in my machine, so I tested my solution with a regular for instead.

Step 1

As you can't use forloop.index because you're filtering out some pages, you need to count the loops by yourself, by writing to a variable with assign.

The following code will just list your pages with a correct loop iterator (by counting just the pages that are actually listed):

{% assign loopindex = 0 %}
{% for page in site.pages %}
{% if page.type == 'project' %}
{% assign loopindex = loopindex | plus: 1 %}
<div class="span3">{{ loopindex }} {{ page.title }}</div>
{% endif %}
{% endfor %}

Step 2

You need to display <div class="row"> with every first row and </div> with every fourth row.

To find the first and fourth rows, you can use modulo:

{% assign loopindex = 0 %}
{% for page in site.pages %}
{% if page.type == 'project' %}
{% assign loopindex = loopindex | plus: 1 %}
{% assign rowfinder = loopindex | modulo: 4 %}
<div class="span3">{{ loopindex }} {{ rowfinder }} {{ page.title }}</div>
{% endif %}
{% endfor %}

rowfinder will always repeat the sequence 1, 2, 3, 0.

Step 3:

So you display <div class="row"> when rowfinder is 1, and </div> when rowfinder is 0:

{% assign loopindex = 0 %}
{% for page in site.pages %}
{% if page.type == 'project' %}
{% assign loopindex = loopindex | plus: 1 %}
{% assign rowfinder = loopindex | modulo: 4 %}
{% if rowfinder == 1 %}
<div class="row">
<div class="span3">{{ page.title }}</div>
{% elsif rowfinder == 0 %}
<div class="span3">{{ page.title }}</div>
</div>
{% else %}
<div class="span3">{{ page.title }}</div>
{% endif %}
{% endif %}
{% endfor %}

Step 4:

Now there's only one small thing left: when the number of pages is not a multiple of 4, there's a </div> missing at the end.

When the number of pages is a multiple of 4, the last value of rowfinder will be 0.

So we just need to display the </div> when the value of rowfinder is anything else but 0.

So just put this after the for loop:

{% if rowfinder != 0 %}
</div>
{% endif %}

...and that's it!



Related Topics



Leave a reply



Submit