Pagination

13 September 2012

Keywords: navigation, paginate

When it comes to pagination, Textpattern offers a rather limited choice. Currently only few tags support pageby attribute, and they don’t play well together. You can not paginate things like custom articles, category lists, comments, and so on. This might change in some future version, but for the moment let us see an etc_query solution.

For illustration, let us paginate something not really pagination-friendly. A good candidate is <txp:category_list /> tag – it supports neither pgonly nor limit/offset attributes. We store its output in some variable:

<txp:variable name="data"><txp:category_list break="" /></txp:variable>

Our <txp:variable name="data" /> will contain 7 links:

<a href="http://www.iut-fbleau.fr/projet/etc/index.php?c=help">Help</a>
...
<a href="http://www.iut-fbleau.fr/projet/etc/index.php?c=tips">Tips</a>

We’d like to paginate them in chunks of 2 categories and access each chunk by some URL parameter, say pgc.

Count pages

First of all, we need to know the total number of pages. The following will store it in <txp:variable name="pages" />:

<txp:etc_query name="pages"
	data='<txp:variable name="data" />'
	query="ceiling(count(a) div 2)" />

Pagination bar

Assuming your urls are in clean mode, we call etc_query again, to generate the navigation bar and store it in <txp:variable name="navbar" />:

<txp:etc_query name="navbar" data="[1..{?pages|1|intval}]">
   <a href="?pgc={#row}">Page {#row}</a>
 </txp:etc_query>

The result will look like

<a href="?pgc=1">Page 1</a>
...
<a href="?pgc=4">Page 4</a>

Another call to etc_query will extract from this list only the links we want to display: first, previous, current, next and last. The position of the “current” link will be given by the url pgc parameter, set to 1 by default:

<txp:etc_query data="{?navbar}" query="a[{?pgc|1|intval}]"
 globals="variable,_GET" wraptag="nav">
   {preceding-sibling::a[position()>1 and position()=last()]=First}
   {preceding-sibling::a[1]=Prev}
   <b>{?}</b>
   {following-sibling::a[1]=Next}
   {following-sibling::a[position()>1 and position()=last()]=Last}
</txp:etc_query>

This pagination bar is fully customizable, but the runtime to generate it grows linearly with the number of articles. The construction can be optimized, but you might prefer another way: etc_pagination will generate it in one go:

<txp:etc_pagination range="0" pages='<txp:variable name="pages" />' pgcounter="pgc" break=" | " link="Page {*}" first="First" prev="Prev" next="Next" last="Last" gap="" />

Page extraction

Finally, we extract from the category list only the page we need:

<txp:etc_query data='<txp:variable name="data" />' query="a"
	globals="_GET" specials="offset"
	limit="2" offset="{?pgc|0|intval.-1.*2}" break="br" />

And here we are:

With some skills and performance tweaks (caching) you can paginate whatever you need, even split a long article in chapters.

File(s)