Skip to content

📖 Paginator Class

Paginator is a service for paginating the results of a pbQuery. It automatically calculates the total number of records, the current and last page, and generates a list of items. The class supports:

  • 🔢 Getting paginated data (items(), total(), currentPage(), etc.);
  • 🖼 Rendering via templates (renderItem, view);
  • 🔗 Navigation link generation (links());
  • ⚡ AJAX functionality (if the pageblocks_load_scripts system setting is enabled).

📰 Displaying News Articles

🚦 Routes

For the news example, we need to register two routes:

php
// web.php (routes)
route('/news', 'NewsController@index')->name('news.index');
route('/news/pagination', 'NewsController@pagination')->name('news.pagination');
  • news.index - displays news with built-in pagination;
  • news.pagination - returns data for AJAX requests.

🎛 Controller

Example NewsController with two methods:

php
class NewsController
{
    // 1. Method to display news
    public function index()
    {
        $paginator = query(\modResource::class)
            ->where(['template' => 5, 'published' => 1])
            ->orderBy('publishedon', 'desc')
            ->paginate(5)
            ->route('news.pagination'); // route for ajax requests

        return view('file:templates/news', [
            'paginator' => $paginator,
        ]);
    }

    // 2. Method to get data (AJAX)
    public function pagination()
    {
        $paginator = query(modResource::class)
            ->where(['template' => 5, 'published' => 1])
            ->orderBy('publishedon', 'desc')
            ->paginate(5);

        return array_merge($paginator->toArray(), [
            'links' => $paginator->links(), // html pagination navigation
            'data' => $paginator->renderItem('file:chunks/news/item.tpl'), // pre-rendered item markup
        ]);
    }
}

🖼 News Template

File: templates/news.tpl

html
<ul>
    {foreach $paginator->items() as $item}
        <li>
            <a href="{$item.uri}">{$item.pagetitle}</a>
            <span class="date">{$item.publishedon|date_format:"%d.%m.%Y"}</span>
        </li>
    {/foreach}
</ul>

<div class="pagination" pb-pagination>
    {$paginator->links()}
</div>

🧩 Single Item Template

File: chunks/news/item.tpl

html
<li>
    <a href="{$uri}">{$pagetitle}</a>
    <span class="date">{$publishedon|date_format:"%d.%m.%Y"}</span>
</li>

🔄 AJAX Functionality

If the pageblocks_load_scripts system setting is enabled, the pagination block:

html
<div class="pb-pagination" pb-pagination>
    {$paginator->links()}
</div>

will be automatically handled by the pbPagination JavaScript class. When a link is clicked, an AJAX request will be sent to the news.pagination route, and the news list will update without a page reload.

📦 Response Format (pagination method)

The pagination() method returns JSON with the following data:

json
{
  "success": true,
  "total": 42,          // total number of news articles
  "count": 5,           // number of items on the current page
  "per_page": 5,        // items per page
  "current_page": 2,    // current page number
  "last_page": 9,       // total number of pages
  "from": 6,            // sequence number of the first news item on the page
  "to": 10,             // sequence number of the last news item on the page
  "data": [ ... ],      // array of news items (query results)
  "links": "<ul>...</ul>", // html pagination navigation
  "data": "<li>...</li><li>...</li>" // pre-rendered item markup (chunk)
}

👉 Note: The data key is overwritten here -

  • the first data comes from $paginator->toArray() (array of items),
  • the second data is the HTML markup for the list (renderItem).

This way, the frontend can either work with JSON data or directly insert the pre-rendered markup.

↕️ Sorting

Now we want to give the user the ability to choose how to sort the news: by date or by title, and in which direction (ASC/DESC).

To do this, the pagination method will accept a Request object:

php
use Boshnik\PageBlocks\Http\Request;

class NewsController
{
    public function pagination(Request $request)
    {
        // determine sorting parameters
        $sortby = $request->get('sortby', 'publishedon'); // sort field
        $sortdir = $request->get('sortdir', 'desc');      // sort direction

        $paginator = query(modResource::class)
            ->where(['template' => 5, 'published' => 1])
            ->orderBy($sortby, $sortdir)
            ->paginate(5);

        return array_merge($paginator->toArray(), [
            'links' => $paginator->links(),
            'data' => $paginator->renderItem('file:chunks/news/item.tpl'),
        ]);
    }
}

🖼 Template with Sort Select

In the news template (templates/news.tpl), let's add a select dropdown with sorting options:

html
<div pb-sort>
	<label for="sort">Sort by:</label>
	<select name="sort">
		<option value="publishedon-desc">Date (Descending)</option>
		<option value="publishedon-asc">Date (Ascending)</option>
		<option value="pagetitle-desc">Title (Descending)</option>
		<option value="pagetitle-asc">Title (Ascending)</option>
	</select>
</div>

<ul id="news-list">
    {foreach $paginator->items() as $item}
        <li>
            <a href="{$item.uri}">{$item.pagetitle}</a>
            <span class="date">{$item.publishedon|date_format:"%d.%m.%Y"}</span>
        </li>
    {/foreach}
</ul>

<div class="pagination" pb-pagination>
    {$paginator->links()}
</div>

🔄 How It Works

  1. The user selects a sorting option from the dropdown.
  2. JavaScript sends an AJAX request to the news.pagination route, adding sortby and sortdir as parameters.
  3. The controller uses them when building the query.
  4. The response is returned as JSON, updating both the list and the pagination.

© PageBlocks 2019-present