David Silva Smith
David Silva Smith

Reputation: 11716

In Jekyll How do I grab a post's first image?

In my index of blog posts I'd like to grab the first image from the post to display it in the index using just liquid so it works on github pages.

I have a feeling split is the way to go, but I'm not good with liquid.

I'd like to be able to get the image url and put it in a variable to style it.

The ideal solution would be something like:

{% for post in site.posts %}
    <li>
      <a href="{{ post.url }}">{{post.content | first_image}}</a>
    </li>
  {% endfor %}

Any ideas?

Upvotes: 27

Views: 10923

Answers (5)

sparanoid
sparanoid

Reputation: 1558

If you just need the image URL instead of the whole thing in img tag, you can use the following method.

Install Liquid filter match_regex:

gem install match_regex

Then add it to your Jekyll config:

plugins:
  - match_regex

Create a capture snippet in your template:

{% capture post_first_image %}
  {% assign hero_image = page.content | match_regex: '<img .*?src="([^"]+)"' %}
  {% if hero_image == nil %}
    {% assign hero_image = "/placeholder-image.png" | prepend: site_base %}
  {% endif %}
  {{ hero_image }}
{% endcapture %}

Template:

<meta property="og:image" content="{{ post_first_image | strip }}">

You can simply remove the if condition if you don't need placeholder image.

Upvotes: 4

Alex Palcuie
Alex Palcuie

Reputation: 4984

I've taken David's answer and found a way to get just the src attribute from the img tag.

    {% assign foundImage = 0 %}
    {% assign images = post.content | split:"<img " %}
    {% for image in images %}
      {% if image contains 'src' %}

          {% if foundImage == 0 %}
              {% assign html = image | split:"/>" | first %}
              {% assign tags = html | split:" " %}
              {% for tag in tags %}
                {% if tag contains 'src' %}
                  <img {{ tag }} />
                {% endif %}
              {% endfor %}
              {% assign foundImage = 1 %}
          {% endif %}
      {% endif %}
    {% endfor %}

Upvotes: 2

J&#250;lio Maia
J&#250;lio Maia

Reputation: 381

You can define a custom variable to your Front Matter called "image", so it's going to work like Wordpress's posts Featured Image:

---
image: featured-image.jpg
---

Note to remember where is your image saved. In my case, I created a directory called "imagens" (PT-BR here). Then, go to your index.html and add the image to your template, wherever you want. In my site it looks like this:

<ul class="post-list">
    {% for post in site.posts %}
      <li>
        <h2>
          <a class="post-link" href="{{ post.url | prepend: site.baseurl }}">{{ post.title }}</a>
        </h2>
        <span class="post-meta">{{ post.date | date: "%b %-d, %Y" }},</span>
        <span class="post-meta">por</span>
        <span class="post-meta">{{ post.author }}</span>
      </li>

      //IMAGE
      <img src="{{ site.baseurl }}/imagens/{{ post.image }}">
      //IMAGE


      {{ post.excerpt }}
      <a class="btn btn-default" href="{{ post.url | prepend: site.baseurl }}">Continuar lendo</a>
    {% endfor %}
  </ul>

That's it.

Upvotes: 28

David Silva Smith
David Silva Smith

Reputation: 11716

Got it to work. Not sure how it will scale, but this liquid code loops through all the posts and grabs the source for the first image from a post and displays that post. I tested it with multiple images and it works as expected.

<ul>
  {% for post in site.posts %}
    <li>

      {% assign foundImage = 0 %}
      {% assign images = post.content | split:"<img " %}
      {% for image in images %}
        {% if image contains 'src' %}

            {% if foundImage == 0 %}
                {% assign html = image | split:"/>" | first %}
                <img {{ html }} />
                {% assign foundImage = 1 %}
            {% endif %}
        {% endif %}
      {% endfor %}

      <a href="{{ post.url }}">{{ post.title }}</a>
    </li>
  {% endfor %}
</ul>

Upvotes: 17

David Jacquel
David Jacquel

Reputation: 52829

Some solutions to your problem :

1 - Use the Post Excerpt tag Documentation is here

Your post :

---
layout: post
title: Testing images
---
## Title
Intro Text
![Image alt]({{ site.baseurl }}/assets/img/image.jpg "image title")
More intro text

Some more text blah !

Your template :

<ul>
  {% for post in site.posts %}
    <li>
      <a href="{{ post.url }}">{{ post.title }}</a>
      {{ post.excerpt }}
    </li>
  {% endfor %}
</ul>

As your image tag appears before the excerpt_separator (\n\n = two newlines) it will be in the post excerpt.

2 - Use your post's Yaml front matter to store your image's datas

Post :

---
layout: post
title: Testing images

images:

  - url: /assets/img/cypripedium-calceolum.jpg
    alt: Cypripedium Calceolum
    title: Cypripedium Calceolum

  - url: /assets/img/hello-bumblebee.jpg
    alt: Hello bumblebee !
    title: Hello bumblebee !
---

Intro here yo ! <-- THIS IS THE EXCERPT

Post body begin, and first image not in excerpt
{% assign image = page.images[0] %} <-- first element of the array is zero
{% include image.html image=image %}

Some more text blah !
{% assign image = page.images[1] %}
{% include image.html image=image %}

_includes/image.html (centralized in an include for standardization, but can be in the template) :

<img src="{{ site.baseurl }}{{ include.image.url }}" alt="{{ include.image.alt }}" title="{{ include.image.title }}">

The index page :

<ul class="posts">
  {% for post in site.posts %}
    <li>
      <span class="post-date">{{ post.date | date: "%b %-d, %Y" }}</span>
      <a class="post-link" href="{{ post.url | prepend: site.baseurl }}">{{ post.title }}</a>
      {{ post.excerpt }}
      {% assign image = post.images[0] %}
      {% include image.html image=image %}
    </li>
  {% endfor %}
</ul>

Upvotes: 19

Related Questions