34

In a Jekyll layout, is there any way to detect if the page is a normal page or a post? I want to display post titles, but not page titles. Like this:

{% if page.is_post? %}
    <h2>{{ page.title }}</h2>
{% endif %}
{{ content }}
Zaz
  • 46,476
  • 14
  • 84
  • 101

6 Answers6

33

Since Jekyll 2.0, you can use Front Matter Defaults:

defaults:
  -
    scope:
      path: ""      # empty string for all files
      type: posts   # limit to posts
    values:
      is_post: true # automatically set is_post=true for all posts

then you can use {{ page.is_post }} to check whether the page is post.

No idea why Jekyll doesn't set page.type by default.

jcubic
  • 61,973
  • 54
  • 229
  • 402
kavinyao
  • 2,951
  • 2
  • 20
  • 23
13

Declaring a post layout in front-matter is not enough? If your post uses a post layout you are sure the page is a post and you don't need to add extra logic

---
layout: post
---

BTW a quick and dirty (very dirty) way to determine the page type consists to check the page path, generally posts are under the _posts directory so you can check it

{% if page.path contains '_posts' %}
This page is a post
{% else %}
This page is a normal page
{% endif %}
dafi
  • 3,492
  • 2
  • 28
  • 51
  • My layout is about 50 lines of HTML, so I don't want two copies that differ by only one line. Thanks for the info though, you've given me an idea how to do this! – Zaz Sep 08 '13 at 16:56
  • @Josh: You can apply a layout to another. – jdh8 Apr 17 '14 at 14:45
13

The easiest and most straightforward way to determine if its a page or a post is to use page.id.

{% if page.id %}
    This is a post
{% endif %}

I personally use this method in my layouts page to determine if its a page or post so I can show links to previous/next posts only if its a post.

_layouts/default.html

<!DOCTYPE html>
<html lang="en">

{% include head.html %}

<body>

{% include header.html %}

{{ content }}

<!-- If this is a post, show previous/next post links -->
{% if page.id %}

{% if page.previous.url %}
<a href="{{page.previous.url}}">{{page.previous.title}}</a>
{% endif %}

{% if page.next.url %}
<a class="button is-link ellipsis" title="{{page.previous.title}}" href="{{page.next.url}}">{{page.next.title}}</a>
{% endif %}

{% endif %}

{% include footer.html %}

</body>
</html>
kimbaudi
  • 13,655
  • 9
  • 62
  • 74
  • Works perfectly for conditional content display in answer to the question posted--thanks! (Not sure why this needed to be voted down, other than some people seem to enjoy doing that on SO.) – SexxLuthor Aug 07 '17 at 04:48
  • All documents in a collection have an id too, so this method doesn't work if your site has collections other than posts. – kslstn May 27 '20 at 12:38
  • @kslstn you can check if it is either a post or a collection using `page.collection`. For example, the following condition would be true if it is a collection and false if it is a post: `{% if page.id and page.collection %}` – kimbaudi May 28 '20 at 04:53
  • 1
    @kimbaudi unless you have posts inside a collection :) – kslstn May 28 '20 at 13:07
9

Here's how I solved the problem:

  1. Create a symlink from _layouts/post_layouts/main
  2. Change the layout of posts to post:

    ---
    layout: post
    ---
    
  3. Add an if statement in _layouts/main like so:

    {% if page.layout == 'post' %}
        <h2>{{ page.title }}</h2>
    {% endif %}
    


A better way to solve this might be to use includes and have two separate layouts like @dafi said though.

Zaz
  • 46,476
  • 14
  • 84
  • 101
1

Posts come with a date variable, while pages do not.

While not bulletproof, this solution requires no additional configuration:

{% if page.date %}
    <h2>{{ page.title }}</h2>
{% endif %}
Ryan Lue
  • 916
  • 10
  • 29
  • 1
    Posts also come with an `id` variable. I personally prefer to use `page.id` to check if its a post. – kimbaudi Jan 28 '17 at 23:43
-1

you can set type, in _config.yml defaults for all types:

defaults:
  - scope:
      path: ""
      type: "pages"
    values:
      type: "pages"
Naser Mirzaei
  • 698
  • 7
  • 11