Internship Report

Paginate Jekyll Posts By Tags

Jekyll currently does't support natively pagination by categories or by tags. So i found a plugin called jekyll-tagging-pagination.

Source code of this plugin: tags-pagination.rb

module Jekyll

  class TagGenerator < Generator
    safe true

    def generate(site)
      if site.layouts.key? 'tag'
        site.tags.keys.each do |tag|
          paginate(site, tag)
        end
      end
    end

    def paginate(site, tag)
      tag_posts = site.posts.find_all {|post| post.tags.include?(tag)}.sort_by {|post| -post.date.to_f}
      num_pages = TagPager.calculate_pages(tag_posts, site.config['paginate'].to_i)

      (1..num_pages).each do |page|
        pager = TagPager.new(site, page, tag_posts, tag, num_pages)
        dir = File.join('tags', tag, page > 1 ? "page#{page}" : '')
        page = TagPage.new(site, site.source, dir, tag)
        page.pager = pager
        site.pages << page
      end
    end
  end

  class TagPage < Page
    def initialize(site, base, dir, tag)
      @site = site
      @base = base
      @dir = dir
      @name = 'index.html'

      self.process(@name)
      self.read_yaml(File.join(base, '_layouts'), 'tag.html')
      self.data['tag'] = tag
      #self.data['title'] = "Posts Tagged &ldquo;"+tag+"&rdquo;"
    end
  end

  class TagPager < Jekyll::Paginate::Pager 
    attr_reader :tag

    def initialize(site, page, all_posts, tag, num_pages = nil)
      @tag = tag
      super site, page, all_posts, num_pages
    end

    alias_method :original_to_liquid, :to_liquid

    def to_liquid
      liquid = original_to_liquid
      liquid['tag'] = @tag
      liquid
    end
  end

end

To use this plugin, create a file called tag.html in the _layout folder. Then put the following code snippet as a start.

{% for post in paginator.posts %}
    {{ post.title }}
{% endfor %}

When Jekyll generates static website, it will also generate a new folder called tags which contains all the tags that you put in your post.

For example, in _site folder, we'll get /tags/cemosis/, /tags/feelpp/, and /tags/csmi/ three folders. Each folder contains paginated folders like page2, page3 ... and one file called index.html for the first page.

The plugin's Readme said we can use paginate.[tag name] to access these files described above, but actually it doesn't work.

So instead I put URL to access directly these html files. Just modify the news link to /tags/cemosis/.

As a result, I must put more HTML and CSS code into tag.html.

---
layout: default
---

<div class="container">
  <div class="row">
    <center><h3>Actualités</h3></center>


{% for post in paginator.posts %}

    {% include news.html %}

{% endfor %}


<!-- Pagination links -->
    {% if paginator.total_pages > 1 %}
    {% assign tag = page.tag %}

    <center>
      {% if paginator.previous_page %}
        <a href="/tags/{{ tag }}{{ paginator.previous_page_path | replace: 'news_', '' | replace: '//', '/' }}">&laquo; Précédente</a>
      {% else %}
        <span>&laquo; Précédente</span>
      {% endif %}

      {% for page in (1..paginator.total_pages) %}
      {% if page == paginator.page %}
        <em>{{ page }}</em>
      {% elsif page == 1 %}
        <a href="/tags/{{ tag }}">{{ page }}</a>
      {% else %}
        <a href="/tags/{{ tag }}{{ site.paginate_path | replace: 'news_/', '' | replace: ':num', page }}">{{ page }}</a>
      {% endif %}
      {% endfor %}

      {% if paginator.next_page %}
        <a href="/tags/{{ tag }}{{ paginator.next_page_path | replace: 'news_', '' | replace: '//', '/' }}">Suivante &raquo;</a>
      {% else %}
        <span>Suivante &raquo;</span>
      {% endif %}
    </center>
    {% endif %}



  </div>
</div>

Now the pagination by tag works fine, but there is another issue: it doesn't care if the paginated post are in the same categories.

So i modified some ruby code in the plugin:

    def paginate(site, tag)
      tag_posts = site.posts.find_all {|post| post.tags.include?(tag) && post.categories.include?(news)}.sort_by {|post| -post.date.to_f}
      ...
      end
    end

And now I get only all the post in news categories with cemosis tag.

The pagination is for now only used in www.cemosis.fr->Vie de Cemosis->Actualité correspond to the folder /tags/cemosis/ under _site.