mayoz/pagination
A lightweight Laravel pagination package that converts arrays, collections, and query results into ready-to-render paginators with customizable views and simple helpers, making it easy to add clean, consistent paging to any app with minimal configuration.
Before writing any code, note the package’s own description: “This package is no longer supported.” With 10 stars and a 0.14 score, it should not be introduced into a new Laravel project. The practical “getting started” path for a developer who inherits it is therefore a triage path rather than an adoption path.
Confirm you actually need it. Laravel ships first-class pagination out of the box:
Model::paginate($perPage) — length-aware pagination (totals + page links)Model::simplePaginate($perPage) — “previous/next” only, one cheaper queryModel::cursorPaginate($perPage) — cursor pagination for large or unstable datasets$users = User::where('active', true)->paginate(15);
return view('users.index', compact('users'));
In almost every case the framework primitive replaces whatever this package wrapped.
If the package is already in composer.json, find it first:
composer show mayoz/pagination
grep -R "Mayoz\|mayoz" app/ config/ resources/ routes/ composer.json
Check composer.lock for the resolved version and whether it is pinned to an old Laravel branch.
First use case to migrate: any controller returning ->paginate() / ->simplePaginate() results, and any Blade view calling {{ $items->links() }}. Replace the package’s facade/helper calls with the native Eloquent builder methods and delete the package’s service provider registration from config/app.php if it is not auto-discovered.
Verify rendering parity. If the package shipped custom Blade views, capture the rendered HTML of one page (php artisan tinker or a feature test) before and after migration so link markup, query-string preservation, and page-size behavior match.
Bottom line: treat this as a legacy dependency to remove, not a tool to learn.
Because the package is unsupported, the patterns below describe how to work around it — either by wrapping it behind your own abstraction while you migrate, or by replacing it with native Laravel pagination.
If the package is used in many controllers, don’t refactor them all at once. Introduce a small repository/query-object layer so pagination calls live in one place:
namespace App\Queries;
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
class UserIndexQuery
{
public function handle(array $filters, int $perPage = 15): LengthAwarePaginator
{
return \App\Models\User::query()
->when($filters['q'] ?? null, fn ($q, $term) => $q->where('name', 'like', "%{$term}%"))
->orderBy('created_at', 'desc')
->paginate($perPage)
->withQueryString(); // keeps filters in links
}
}
Controllers then depend only on LengthAwarePaginator, and the package can be swapped out underneath without touching call sites.
The most common day-to-day regression when replacing any pagination package is losing filters on page 2. Always chain:
$users = $query->paginate($request->integer('per_page', 15))->withQueryString();
And validate per_page against an allow-list so clients can’t request 100,000 rows:
$perPage = in_array($request->integer('per_page'), [10, 25, 50, 100], true)
? $request->integer('per_page')
: 15;
For JSON endpoints, let the paginator serialize itself rather than hand-building the envelope:
return UserResource::collection($query->paginate(20));
This yields data, links, and meta consistently — a strong reason not to rely on a third-party wrapper.
For infinite-scroll or high-churn tables, prefer cursorPaginate(); it avoids OFFSET costs and duplicate rows when data shifts between requests:
$feed = Post::orderByDesc('id')->cursorPaginate(25);
If the package provided custom Blade components, recreate them as a single partial that calls the native links:
{{-- resources/views/partials/pagination.blade.php --}}
@if ($paginator->hasPages())
{{ $paginator->links() }}
@endif
Keep the presentation in one partial so template changes are a one-file edit.
$this->get('/users?q=ali&page=2')->assertOk()->assertSee('ali');
Illuminate\Pagination\Paginator, audit Paginator::useBootstrap*() / useTailwind() calls in AppServiceProvider — those are framework-level and survive package removal.config/pagination.php) and delete it during cleanup to avoid dead config.Abandonment is the headline risk. “No longer supported” means no security patches, no Laravel 11/12 compatibility guarantees, and no upstream fixes for PHP 8.x deprecations. Composer will happily install it, but you own every future breakage. Do not add it to new work; schedule removal in existing work.
Version pinning is fragile. Unmaintained pagination packages tend to declare tight illuminate/* constraints. When you upgrade Laravel, Composer may fail to resolve or may silently keep you on an old framework branch. Check composer why-not laravel/framework before upgrading and budget time to remove the package as part of that upgrade.
Name-collision and facade confusion. Laravel already exposes Illuminate\Pagination\* classes and a Paginator facade alias. If the package registers its own Paginator or LengthAwarePaginator, you can end up type-hinting the wrong class in controllers — a subtle bug where instanceof checks pass in one path and fail in another. After removal, run:
composer dump-autoload -o
grep -R "use .*Pagination" app/
to catch stale imports.
Debugging pagination issues is almost always a query-string or count problem. When page links misbehave:
dd($paginator->url(2)) to inspect the generated URL and confirm filters are carried.->withQueryString(); without it, filters vanish on subsequent pages.groupBy/having query — paginate() uses a count subquery that some SQL shapes break. Switch to simplePaginate() or a manual count in those cases.paginate() runs an extra COUNT(*); if that dominates your profile, use simplePaginate() or cursorPaginate().Extension point worth knowing. Blade pagination views are publishable in the framework:
php artisan vendor:publish --tag=laravel-pagination
This gives you resources/views/vendor/pagination/*.blade.php. Customize there rather than in a third-party package’s views — you keep the extension point even after removing the dependency.
If you must run it temporarily, treat it as hostile:
composer.json ("mayoz/pagination": "x.y.z") so a stray update can’t shift behavior.// TODO: remove mayoz/pagination comment and a tracking ticket with an owner and date.composer audit in CI; abandoned packages may not surface advisories, so also check the repo’s last commit date manually.Migration checklist (the real “tip” for this package):
grep -R "mayoz\|pagination" app/ resources/ config/.paginate() / simplePaginate() / cursorPaginate().->withQueryString() everywhere filters exist.resources/views/vendor/pagination.composer remove mayoz/pagination.php artisan config:clear && php artisan view:clear.data / links / meta).When to reach for alternatives. If native pagination truly isn’t enough (e.g., keyset pagination with complex sorting, or fancy UI components), choose a maintained package — Laravel’s own primitives, spatie/laravel-query-builder for filter/sort/paginate APIs, or a UI library for the front end — rather than reviving an unsupported one.
How can I help you explore Laravel packages today?