Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Jekyll exclude tag from pagination

I have some posts tagged with foo, and I want to exclude those from my front page.

I have tried putting this code into the front-page template:

<div class="posts">
  {% for post in paginator.posts %}
  {% unless post.tags and post.tags contains "foo" %}

  {% endunless %}
  {% endfor %}
</div>

However this results in the pagination being incorrect.

Here are some example posts:

+-------+--------+-----+
| Index |  Post  | Tag |
+-------+--------+-----+
|     1 | Red    | foo |
|     2 | Blue   |     |
|     3 | White  |     |
|     4 | Pink   | foo |
|     5 | Orange |     |
|     6 | Yellow | foo |
|     7 | Beige  | foo |
|     8 | Purple |     |
|     9 | Black  | foo |
+-------+--------+-----+

Actual output:

  1. Page 1: 2, 3, 5
  2. Page 2: 8

What I would like:

  1. Page 1: 2, 3, 5, 8

As you can see it is currently splitting the posts into blocks of 5 and then my code filters them - I would like to apply the filtering before the pagination is calculated.

like image 618
James Monger Avatar asked Oct 13 '17 11:10

James Monger


3 Answers

Just add hidden: true variable in yaml frontmatter for posts not to appear in home page pagination. See this.

While this doesn't filter by tags (you'd need to go through posts one by one and add the option manually) it seems much simpler than the tweaks suggested above.

And pagination for your first and second pages remains correct.

like image 195
emagar Avatar answered Oct 24 '22 01:10

emagar


It can't be done without hacking the paginator plugin, so here we go:

  1. remove gem jekyll-paginate from Gemfile

  2. set the needed configuration variables in _config.yml:

     paginate: 2
     paginate_path: "/blog/page:num/"
    
  3. create the _plugins directory

  4. copy pager.rb and pagination.rb to _plugins/

     cd _plugins
     wget https://github.com/jekyll/jekyll-paginate/blob/master/lib/jekyll-paginate/pager.rb
     wget https://github.com/jekyll/jekyll-paginate/blob/master/lib/jekyll-paginate/pagination.rb
    
  5. display posts in homepage with the suggested code used in docs

    <!-- This loops through the paginated posts -->
    {% for post in paginator.posts %}
      <h1><a href="{{ post.url }}">{{ post.title }}</a></h1>
      <p class="author">
    <span class="date">{{ post.date }}</span>
      </p>
      <div class="content">
    {{ post.content }}
      </div>
    {% endfor %}
    
    <h1>  Paginator</h1>
    <!-- Pagination links -->
    <div class="pagination">
      {% if paginator.previous_page %}
    <a href="{{ paginator.previous_page_path }}" class="previous">Previous</a>
      {% else %}
    <span class="previous">Previous</span>
      {% endif %}
      <span class="page_number ">Page: {{ paginator.page }} of {{ paginator.total_pages }}</span>
      {% if paginator.next_page %}
    <a href="{{ paginator.next_page_path }}" class="next">Next</a>
      {% else %}
    <span class="next ">Next</span>
      {% endif %}
    </div>
    
  6. In pagination.rb modify the paginate function to filter your posts containing the tag foo, currently the all_posts variable contains all the posts data used to calculate pagination, so we need to remove the ones that contains the tag with:

           all_posts = all_posts.select do |elem|
             !elem.data['tags'].include? 'foo'
           end
    

    Then the function will look like:

         def paginate(site, page)
           all_posts = site.site_payload['site']['posts'].reject { |post| post['hidden'] }
           all_posts = all_posts.select do |elem|
             !elem.data['tags'].include? 'foo'
           end
           pages = Pager.calculate_pages(all_posts, site.config['paginate'].to_i)
           (1..pages).each do |num_page|
             pager = Pager.new(site, num_page, all_posts, pages)
             if num_page > 1
               newpage = Page.new(site, site.source, page.dir, page.name)
               newpage.pager = pager
               newpage.dir = Pager.paginate_path(site, num_page)
               site.pages << newpage
             else
               page.pager = pager
             end
           end
         end
    

Then page 1 will show the desired posts, only the ones not containing the foo tag: 2, 3, 5, 8.

like image 2
marcanuy Avatar answered Oct 24 '22 00:10

marcanuy


[updated answer]

Solution 1. New collection

You reported that the where command on the paginator object does not work/recalculate the paging. Therefore, I would advice to save all 'foo' posts in a separate collection. This solves your original problem, but creates a new problem if you want to show all posts combined on another page. If you do not want that, this is the most elegant solution.

Solution 2. Use Javascript for paging

Forget about the paginator object and solve this by building you own paging (or infinte scroll) in Javascript, since pagination is a SEO issue anyway...

Note: I have created a resource for Jekyll without plugins. I will add Javascript pagination here too.

like image 1
JoostS Avatar answered Oct 23 '22 23:10

JoostS