Pagination
Basic Pagination of JSON Array
Pagination can be automatically handled by Eleventy. Front matter in a template is used to indicate what data is paginated, and how many items per page there should be.
Create a new _data/fishList.json file containing an array (this one has 13 items) :
[ "perch", "bass", "bream", "flounder", "salmon", "mackerel", "trout", "sardine", "anchovy", "swordfish", "tuna", "carp", "guppy" ]
Create the file fishpaged.html. In the front matter there will be a pagination variable which contains what data to paginate (data: fishList) and how many items per page (size: 2). The following for loop iterates through the resulting pagination items.
--- title: Fish Paged pagination: data: fishList size: 2 --- {% include _head.html %} <h1>{{ title }}</h1> <ul> {% for fish in pagination.items -%} <li>{{ fish }}</li> {% endfor -%} </ul> {% include _foot.html %}
You should now find a _site/fishpaged folder, containing an index.html and folders numbered 1 to 6, each containing an index.html. The _site/fishpaged/index.html should contain :
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Animals Paged</title> </head> <body> <h1>Animals Paged</h1> <ul> <li>perch</li> <li>bass</li> </ul> <p>Footer text</p> </body> </html>
Each subfolder's index file (e.g. _site/fishpaged/1/index.html) should have two more of the fish from the JSON file, with the 6th one only having "guppy". Again, the idea is to result in a clean URL structure, e.g. http://localhost/eleventy/eleventy-test/_site/fishpaged/1/, then http://localhost/eleventy/eleventy-test/_site/fishpaged/2/, etc.
Pagination of JSON object
Pagination of a JSON object is only slightly different. Edit _site/fishList.json to contain :
{ "fish": [ "perch", "bass", "bream", "flounder", "salmon", "mackerel", "trout", "sardine", "anchovy", "swordfish", "tuna", "carp", "guppy" ] }
Edit fishpaged.html so the front matter is :
--- title: Fish Paged pagination: data: fishList.fish size: 2 ---
Pagination Object
It's helpful to look at the actual organization of the data in the Pagination object, to see how it can be used in a template.
{ items: [], /* an array of the content in the pages */ pageNumber: 0, /* the current page number, starting at 0 */ hrefs: [], /* an array of the paths of the pages*/ href: { next: "", /* relative to the current page, the path for the next page, can be used in a "next page" link */ previous: "", /* relative to the current page, the path for the next page, can be used in a "previous page" link */ first: "", /* the path for the first page, can be used in a "first page" link */ last: "", /* the path for the last page, can be used in a "last page" link */ }, pages: [], /* an array of the unformatted data in the pages */ page: { next: "", /* relative to the current page, unformatted data of the next page */ previous: "", /* relative to the current page, unformatted data of the previous page */ first: "", /* unformatted data of the first page */ last: "", /* unformatted data of the last page */ } }
In fishpaged.html, there is a loop that cycles through the pagination.items array, and displays the content in a list. The other values in this object can be inserted into the template for creating navigation links or showing the page number. These values can also be used for modifying the page permalinks.
Customizing the Permalinks
The Eleventy default for the pagination folder structure can be overriden in the front matter. The syntax uses template tags, the only time they can be used in front matter.
Delete the _site folder, then edit fishpaged.html so the front matter is :
--- title: Fish Paged pagination: data: fishList.fish size: 2 permalink: "fishes/page-{{ pagination.pageNumber }}/index.html" ---Instead of a _site/fishpaged folder, there should now be a _site/fishes folder, with subfolders like _site/fishes/page-0/, then _site/fishes/page-1/, etc.
Note how this time, there is no index.html in _site/fishes, instead there is the _site/fishes/page-0/ which has the page for the first two items (perch and bass).
To have the folders start with page-1, change the permalink value to :
permalink: "fishes/page-{{ pagination.pageNumber | plus: 1 }}/index.html"
As previously seen, by default, Eleventy structured the pagination so that we got :
_site/fishpaged/index.html _site/fishpaged/1/index.html _site/fishpaged/2/index.html ...
Then we were able to customize it to be structured as :
_site/fishes/page-1/index.html _site/fishes/page-2/index.html _site/fishes/page-3/index.html ...
With no fishes/index.html.
But what might be preferred is a main page with no number, then the second page is numbered "2" :
_site/fishes/index.html _site/fishes/page-2/index.html _site/fishes/page-3/index.html ...
This way the URL for the first fishes page is a little cleaner. This can be done by adding a conditional to the permalink front matter:
permalink: "fishes/{% if pagination.pageNumber>0 %}page-{{ pagination.pageNumber | plus: 1 }}{% endif %}/index.html"
In all cases, it uses the fishes/ folder. It then checks if the page number is above 0, and if true, creates page-*/index.html (adding 1 to the page number). For page 0 it just creates the index.html.
This is the Liquid syntax, Nunjucks will be different. A lot of things can be done with pagination, refer to the Eleventy documentation for more details.
Page Navigation
With the pagination object, the pagination.href.previous and pagination.href.next values can be used to create Previous and Next links, and with added conditionals to decide if links should be created on a particular page.
Note: Eleventy thinks of the site root as being _site, especially when generating its own URLs. This is where runnning Eleventy's server (or some other server) makes working on pagination much easier.
Edit fishpaged.html to add the needed tags :
--- title: Fish Paged pagination: data: fishList.fish size: 2 permalink: "fishes/{% if pagination.pageNumber>0 %}page-{{ pagination.pageNumber | plus: 1 }}{% endif %}/index.html" --- {% include _head.html %} <h1>{{ title }}</h1> <ul> {% for fish in pagination.items -%} <li>{{ fish }}</li> {% endfor -%} </ul> <hr> <ul> <li>{% if pagination.href.previous %}<a href="{{ pagination.href.previous }}">Previous</a>{% else %}Previous{% endif %}</li> <li>{% if pagination.href.next %}<a href="{{ pagination.href.next }}">Next</a>{% else %}Next{% endif %}</li> </ul> {% include _foot.html %}
Load the first page in your browser, /fishes/ and there should be list items for Previous and Next. Next should be a link. Navigation across the paginated content with these list items should be possible.
To add links for the first and last pages, there are respective values for those as well (pagination.href.first and pagination.href.last):
<ul> <li><a href="{{ pagination.href.first }}">First</a></li> <li>{% if pagination.href.previous %}<a href="{{ pagination.href.previous }}">Previous</a>{% else %}Previous{% endif %}</li> <li>{% if pagination.href.next %}<a href="{{ pagination.href.next }}">Next</a>{% else %}Next{% endif %}</li> <li><a href="{{ pagination.href.last }}">Last</a></li> </ul>
To add a page number to the navigation area, insert pagination.pageNumber into the HTML. Because pageNumber starts at "0", add "1" to display standard page numbering. Edit fishpaged.html to add the needed tag :
<ul> <li><a href="{{ pagination.href.first }}">First</a></li> <li>{% if pagination.href.previous %}<a href="{{ pagination.href.previous }}">Previous</a>{% else %}Previous{% endif %}</li> <li> Page {{ pagination.pageNumber | plus: 1 }} </li> <li>{% if pagination.href.next %}<a href="{{ pagination.href.next }}">Next</a>{% else %}Next{% endif %}</li> <li><a href="{{ pagination.href.last }}">Last</a></li> </ul>
Load the first page in your browser, /fishes/ and there should now be a Page 1 in between the Previous and Next list items. Navigating through the pages should be reflected in that number's value.