Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

visyonDevelopers's avatar

Custom pagination (variable quantity of items per page)

I was wondering if there is some example out there about how to implement a paginator which shows 'n' results on first page and then 'm' on following pages (being 'n' > 'm').

The app I'm developing has no views (its responses will be JSON objects), so my concerns aren't on how to implement a Presenter, but some way to be able to show a certain amount of items on the first page, and then a different amount of items on next pages.

For example, the function would be:

$this->model->paginateCustomMethod(10, 15)

which would show 10 items on the first page, then 15 on the subsequent. I'd like to implement the same behavior as this: Different number of items on first page

Does that have any sense? Any ideas or examples?

0 likes
5 replies
jekinney's avatar

When I needed to do similar I had the first query set as limit(10). Then subsequent queries use skip()->take() on the base query.

visyonDevelopers's avatar

Hmm... I was looking for a more 'sophisticated' solution, such as leaving this work to the paginator itself.

But I can give a try to your solution, will update if that worked for me.

vitorf7's avatar

@developers@visyon360.com I know this is very late and I had the same question. Did you manage to solve this? If so how? I had a similar problem as I wanted to do a Load More kind of pagination with 9 items on first page and 3 on each load. I wrote a small trait that kind of used some of the techniques some of the other people answered. This is what I managed to do:

/**
 * LoadMorePagination Trait
 *
 * Adds an easy way to paginate a Model's Results with an
 * initial amount of items on the first page and then
 * have a different quantity for subsequent pages
 *
 * @author Vitor Faiante
 */
trait LoadMorePagination
{
    /**
     * Paginate Load More
     *
     * Paginates an eloquent Model's results with an initial quantity of items
     * on the first page and then another quantity on subsequent pages
     *
     * @param  Illuminate\Database\Query\Builder $query     [An Eloquent Query Builder]
     * @param  integer $initialQuantity [Quantity of items on the first page]
     * @param  integer $loadMore        [Quantity of items on subsequent pages]
     * @param  Illuminate\Database\Eloquent\Model $model [An Eloquent Model]
     *
     * @return array [Array of results and pagination information]
     */
    public function paginateLoadMore($initialQuantity = 9, $loadMore = 3, $model = null)
    {
        // If no model is passed as last argument and current class is not an Eloquent Model then abort
        abort_if(
            ($model === null && !$this instanceof Model),
            404,
            'Please provide an Eloquent Model Class as the last argument or use this in an Eloquent Model Class'
        );

        // Model is either the model passed as last argument or the Class in case it is null
        $model = $model ?: $this;

        $page = (int) Paginator::resolveCurrentPage();
        $perPage = ($page == 1) ? $initialQuantity : $loadMore;
        $skip = ($page == 1) ? 0 : ($initialQuantity + ($loadMore * ($page - 2)));

        // Get a full collection to be able to calculate the full total all the time
        $modelCollection = $model->get();
        // Get the correct results
        $modelResults = $model->skip($skip)->take($perPage)->get();

        $total = $modelCollection->count();
        $lastPage = (int) round(($total - $initialQuantity) / $loadMore + 1);
        $from = $skip + 1;
        $to = $skip + $perPage;
        $nextPageUrl = ($page !== $lastPage) ? (string) Paginator::resolveCurrentPath() . '?page=' . ($page + 1) : null;
        $previousPageUrl = ($page !== 1) ? (string) Paginator::resolveCurrentPath() . '?page=' . ($page - 1) : null;

        return [
            'current_page' => $page,
            'per_page' => $perPage,
            'total' => $total,
            'last_page' => $lastPage,
            'from' => $from,
            'to' => $to,
            'previous_page_url' => $previousPageUrl,
            'next_page_url' => $nextPageUrl,
            'data' => $modelResults->toArray()
        ];
    }

    /**
     * Query Scope paginateLoadMore
     *
     * This method is will be used when chaining a model with other methods
     * such as with() relationship methods
     *
     * @param  Illuminate\Database\Query\Builder $query     [An Eloquent Query Builder]
     * @param  integer $initialQuantity [Quantity of items on the first page]
     * @param  integer $loadMore        [Quantity of items on subsequent pages]
     * @param  Illuminate\Database\Eloquent\Model $model [An Eloquent Model]
     *
     * @return paginateLoadMore
     */
    public function scopePaginateLoadMore($query, $initialQuantity = 9, $loadMore = 3, $model = null)
    {
        return $this->paginateLoadMore($initialQuantity, $loadMore, $query);
    }
}

This is used in a Repository but you could always remove the model and use it like you wanted in the Model too.

Please or to participate in this conversation.