On This Page
Jekyll’s default pagination plugin is great for generating paginated pages, but it has a major limitation—it only works with URLs like /page/2/
instead of /2.html
. If you want pagination with custom page filenames like 2.html
, 3.html
, and so on, you need a custom pagination plugin.
Pagination for categories, tags and collections jekyll-paginate-v2
plugin can be used but this plugin is not supported by GitHub Pages. I you have blog page /blog
and want clean pagination like /blog/2
, /blog/3
you can use this plugin.
Create Jekyll Plugin
Create a file named _plugins/custom_pagination.rb
and add the following code:
module Jekyll
class Pagination < Generator
safe true
def generate(site)
if site.config['pagination']['active']
paginate(site)
end
end
def paginate(site)
all_posts = site.posts.docs.reverse
paginate_size = site.config['pagination']['paginate'].to_i
total_pages = (all_posts.size / paginate_size.to_f).ceil
(1..total_pages).each do |current_page|
pager = Pager.new(site, current_page, all_posts, total_pages, paginate_size)
index_page = HomeIndexPage.new(site, current_page)
index_page.pager = pager
site.pages << index_page
end
end
end
class Pager
attr_reader :current_page, :total_pages, :posts, :previous_page, :next_page
def initialize(site, current_page, all_posts, total_pages, paginate_size)
@current_page = current_page
@total_pages = total_pages
start = (current_page - 1) * paginate_size
@posts = all_posts.slice(start, paginate_size)
@previous_page = current_page > 1 ? current_page - 1 : nil
@next_page = current_page < total_pages ? current_page + 1 : nil
end
def to_liquid
{
'current_page' => @current_page,
'total_pages' => @total_pages,
'posts' => @posts,
'previous_page' => @previous_page,
'next_page' => @next_page
}
end
end
class HomeIndexPage < Page
def initialize(site, current_page)
@site = site
@base = site.source
@dir = '/'
@name = current_page == 1 ? 'blog.html' : "blog/#{current_page}.html"
self.process(@name)
self.read_yaml(File.join(@base, '_layouts'), 'blog.html')
self.data['title'] = "Page #{current_page}" if current_page > 1
end
end
end
Creat Blog Layout
Create a blog page layout named _layouts/blog.html
and add the following code:
---
layout: default
title: Blog
---
<ul class="post-list">{% for post in paginator.posts %}
<li>
<a href="{{ post.url }}">{{ post.title }}
</a>
</li>{% endfor %}
</ul>
<div class="pagination">{% if paginator.previous_page %}
{% if paginator.previous_page == 1 %}
<a href="/blog">Previous</a>{% else %}
<a href="/blog/{{ paginator.previous_page }}">Previous</a>{% endif %}
{% endif %}
<!-- Page numbers -->{% for page in (1..paginator.total_pages) %}
{% if page == paginator.current_page %}
<span class="current">{{ page }}</span>{% else %}
{% if page == 1 %}
<a href="/blog">1</a>{% else %}
<a href="/blog/{{ page }}">{{ page }}</a>{% endif %}
{% endif %}
{% endfor %}
{% if paginator.next_page %}
<a href="/blog/{{ paginator.next_page }}">Next</a>{% endif %}
</div>
Config
pagination:
active: true
paginate: 20 # Number of posts per page
With these steps, you now have a custom pagination solution that generates clean .html files for each page of your blog.