spatie/laravel-paginateroute
Adds a Laravel route macro to paginate via clean, translatable URLs like /news/page/2 instead of ?page=2. Includes a paginate route method and facade for generating pagination links. Note: this package is abandoned/unsupported—fork if needed.
Installation:
composer require spatie/laravel-paginateroute
Publish the config (if needed):
php artisan vendor:publish --provider="Spatie\PaginateRoute\PaginateRouteServiceProvider"
Basic Usage:
Define a route with paginate() method:
Route::paginate('news', 'news/{page}', function () {
return News::paginate(10);
});
This generates routes like /news/1, /news/2, etc., instead of /news?page=2.
First Use Case:
Replace traditional paginated routes (e.g., Route::get('/news', 'NewsController@index')) with paginate() for cleaner URLs and better i18n support.
Route Definition:
Use Route::paginate($baseUri, $uriPattern, $closure):
Route::paginate('posts', 'posts/{page}', function () {
return Post::paginate(15);
});
$baseUri: Base path (e.g., admin for /admin/posts/2).$uriPattern: Customize the page parameter (e.g., blog/{page} or posts/page/{id}).Controller Integration: Reuse existing paginated queries:
public function index() {
return Post::paginate(10); // Works with or without the package
}
The package automatically handles the route logic.
Dynamic Segments: Combine with route model binding:
Route::paginate('users/{user}', 'users/{user}/posts/{page}', function ($user) {
return $user->posts()->paginate(8);
});
Middleware: Apply middleware to paginated routes:
Route::paginate('admin/posts', 'admin/posts/{page}')
->middleware('auth.admin');
Custom Pagination Logic: Override the default pagination behavior in the closure:
Route::paginate('search', 'search/{page}', function ($page = 1) {
return Product::where('name', 'like', '%' . request('q') . '%')
->paginate(20, ['page' => $page]);
});
API Integration: Use with API resources for consistent pagination:
Route::paginate('api/posts', 'api/posts/{page}', function () {
return new PostResource(Post::paginate(12));
});
Localization:
Leverage translatable routes (e.g., /news/page/2 → /nieuws/pagina/2):
Route::paginate('news', 'news/{page}', function () {
return News::paginate(10);
});
Update language-specific routes in your routes/web.php:
if (app()->getLocale() === 'nl') {
Route::paginate('nieuws', 'nieuws/pagina/{page}', function () {
return News::paginate(10);
});
}
Caching: Cache paginated responses (e.g., for static pages):
Route::paginate('static', 'static/{page}')
->middleware('cache.headers:public;max_age=3600');
Abandoned Package:
spatie/laravel-query-builder + custom routes.Route Conflict:
/posts/1 vs. /posts/1/edit) may cause ambiguity.Route::paginate('posts', 'posts/page/{page}')
->name('posts.page');
Pagination Parameter Override:
$page as the first argument, which may conflict with existing logic.request()->page:
function ($customPage = null) {
$page = $customPage ?? request()->page;
return Model::paginate(10, ['page' => $page]);
}
Laravel Version Compatibility:
composer.json constraints or patch the package.Route Listing:
Use php artisan route:list to verify paginated routes are registered:
| | GET|HEAD | paginate | posts/{page} | Spatie\PaginateRoute\PaginateRouteController@__invoke | app.Http\Controllers\PaginateRouteController |
Closure Debugging:
Add dd($page) in the closure to inspect the page parameter:
Route::paginate('debug', 'debug/{page}', function ($page) {
dd($page); // Check if it's 1, 2, etc.
return Model::paginate(5);
});
Middleware Debugging:
Use php artisan route:list --verbose to confirm middleware is applied.
Custom Page Parameter:
Modify the config/paginateroute.php to change the default page parameter name (e.g., p instead of page):
'page_param' => 'p',
Override Default Controller:
Bind a custom controller in AppServiceProvider:
public function boot() {
Route::bind('paginate', function ($page) {
return new CustomPaginateController($page);
});
}
Add Query Parameters:
Preserve query strings (e.g., /posts?filter=active/page/2):
Route::paginate('posts', 'posts/{page}', function ($page) {
return Post::where('active', true)->paginate(10, ['page' => $page]);
});
Ensure your closure handles request()->query() manually if needed.
Avoid N+1 Queries:
Use with() or eager loading in paginated queries:
Route::paginate('posts', 'posts/{page}', function () {
return Post::with('author')->paginate(10);
});
Cursor Pagination:
For large datasets, combine with cursor-based pagination (e.g., simple-pagination package):
Route::paginate('large-data', 'data/{page}', function () {
return Model::orderBy('id')->simplePaginate(50);
});
How can I help you explore Laravel packages today?