Middleman Pagination

Build Status Code Climate Dependency Status Gem Version

General-purpose pagination support for Middleman.

Middleman resources, proxy pages, and any arbitrary collection of objects can be paginated.

Installation

Add this line to your Middleman site's Gemfile:

gem 'middleman-pagination'

And then execute:

$ bundle

Or install it yourself as:

$ gem install middleman-pagination

Usage

Let's say you have a set of recipes that you want to create pagination for:

source/
    all-recipes.html
    recipes/
        apple-pie.html
        bacon.html
        cake.html

Inside your config.rb:

activate :pagination do
  pageable_resource :recipes do |page|
    # Match any page that lives in the "recipes" directory
    page.path.start_with?('recipes/')
  end
end

Note: If you're using the directory indexes extension, place it after activate :directory_indexes.

Now, let's set up a pagination index. Inside all-recipes.html:

---
pagination:
  for: recipes
  per_page: 20
---

<% pagination.each do |recipe| %>
  - <%= link_to recipe.data.title, recipe.url %>
<% end %>

Page <%= pagination.page_num %> of <%= pagination.total_page_num %>

Showing <%= pagination.per_page %> per page

<%= link_to "First page", pagination.first_page.url %>

<%= link_to "Prev page", pagination.prev_page.url if pagination.prev_page %>

<%= link_to "Next page", pagination.next_page.url if pagination.next_page %>

<%= link_to "Last page", pagination.first_page.url %>

Note: the for and per_page properties must be indented for the pagination frontmatter (per_page is optional).

You can define as many different types of pageable resources as you like, with whatever criteria you like:

activate :pagination do
  pageable_resource :staff do |page|
    # Match any page whose URL includes "/staff/"
    page.url.include?('/staff/')
  end

  pageable_resource :news do |page|
    # Match any page that has a "news" property in its frontmatter
    page.data.news.present?
  end
end

Custom path

If your pagination index is called all-recipes.html, the subsequent pages will ba named all-recipes/pages/2.html, all-recipes/pages/3.html, and so on.

You can customise the path with the path pagination frontmatter. For example, in all-recipes.html:

---
pagination:
  for: recipes
  path: p/:num
---

Your pages would be created at all-recipes/p/2.html, all-recipes/p/3.html, etc.

Paginate data

You aren't limited to just pages. You can paginate over Middleman Local Data, too.

Let's say you had a file called roman_gods.yml in your data directory:

- name: Jupiter
  title: King of the Gods
- name: Juno
  title: Queen of the Gods
- name: Neptune
  title: God of the Sea
- name: Pluto
  title: God of Death

...snip...

You can produce pagination by using pageable_set:

activate :pagination do
  pageable_set :gods do
    data.roman_gods
  end
end

In your template:

---
pagination:
  for: gods
  per_page: 10
---

<% pagination.each do |god| %>
  - <%= god.name %> (<%= god.title %>)
<% end %>

<%= link_to "Next page", pagination.next_page.url if pagination.next_page %>

Paginate anything

In fact, you can paginate any collection of objects that responds to each, by using pageable_set:

activate :pagination do
  pageable_set :planets do
    ['Mercury', 'Venus', 'Earth', 'Mars', 'Jupiter', 'Saturn', 'Uranus', 'Neptune']
  end
end

The set can be used in exactly the same way:

---
pagination:
  for: planets
  per_page: 4
---

Planets (showing <%= pagination.per_page %> per page):

<% pagination.each do |planet| %>
  - <%= planet %>
<% end %>

<%= link_to "Next page", pagination.next_page.url if pagination.next_page %>

Getting help

Bug? Feature request? You can open an issue, contact me on Twitter, or start a new topic on the Middleman forums. All feedback and suggestions welcome.

TODO

  • Custom sorting (e.g. by date)
  • Add tests for metadata support
  • Convenience helper methods (e.g. make pagination. optional)
  • Pagination link generator (e.g. Pages: 1 2 [3] ... 7 8 9)
  • Adopt Middleman's Queryable interface (potentially requires changes to Middleman first)

Contributing

  1. Fork it
  2. Create your feature branch (git checkout -b my-new-feature)
  3. Commit your changes (git commit -am 'Add some feature')
  4. Push to the branch (git push origin my-new-feature)
  5. Create new Pull Request