Customizing Laravel Pagination for Pseudo‑Static URLs
This guide explains how to override Laravel's built‑in pagination component to generate clean pseudo‑static URLs by creating a custom LengthAwarePaginator, rewriting its url method, and providing a staticPaginate scope for selective use.
In a Laravel project the built‑in pagination component generates URLs with query parameters, which does not satisfy the requirement for pseudo‑static URLs such as /software/3dmax/created_at/page-1.html .
The desired routing pattern is /software/{category}/{order}/page-{page}.html , but the default paginator produces URLs like /software/3dmax/created_at/page-1.html?category=3dmax&order=created_at&page=2 .
To achieve the required format we need to override the Laravel paginator. First create a custom paginator class that extends Illuminate\Pagination\LengthAwarePaginator :
<code>mkdir app/Pagination
touch app/Pagination/LengthAwarePaginator.php</code>File app/Pagination/LengthAwarePaginator.php :
<code><?php
namespace App\Pagination;
use Illuminate\Support\Arr;
use Illuminate\Support\Str;
use Illuminate\Pagination\LengthAwarePaginator as BasePaginator;
class LengthAwarePaginator extends BasePaginator
{
}
</code>Then rewrite the url method to move route parameters from the query string into the path while preserving other query parameters:
<code>public function url($page)
{
if ($page <= 0) {
$page = 1;
}
$parameters = [$this->pageName => $page];
if (count($this->query) > 0) {
$parameters = array_merge($this->query, $parameters);
}
// parameters bound to the route
$params = \request()->route()->parameters();
if (!empty($params)) {
foreach ($parameters as $key => $parameter) {
if (isset($params[$key])) {
$params[$key] = $parameter;
unset($parameters[$key]);
}
}
$path = route(\request()->route()->getAction('as'), $params);
} else {
$path = $this->path;
}
// if no remaining query parameters
if (empty(Arr::query($parameters))) {
return $path . $this->buildFragment();
}
return $path
. (Str::contains($this->path, '?') ? '&' : '?')
. Arr::query($parameters)
. $this->buildFragment();
}
</code>Next, replace the default paginator with the custom one in the application’s service container:
<code># replace
use App\Pagination\LengthAwarePaginator;
# --- use Illuminate\Contracts\Pagination\LengthAwarePaginator; // commented
...
/**
* @param \Illuminate\Support\Collection $items
* @param int $total
* @param int $perPage
* @param int $currentPage
* @param array $options
* @return LengthAwarePaginator
*/
protected function paginator($items, $total, $perPage, $currentPage, $options)
{
return Container::getInstance()->makeWith(LengthAwarePaginator::class, compact(
'items', 'total', 'perPage', 'currentPage', 'options'
));
}
</code>For cases where only some pages need pseudo‑static URLs, define a local scope staticPaginate in a base model class:
<code>public function scopeStaticPaginate($builder, $perPage = null, $columns = ['*'], $pageName = 'page', $page = null)
{
if (request('page')) {
request()->offsetSet('page', request('page'));
}
$page = $page ?: Paginator::resolveCurrentPage($pageName);
$perPage = $perPage ?: $builder->getModel()->getPerPage();
$results = ($total = $builder->toBase()->getCountForPagination())
? $builder->forPage($page, $perPage)->get($columns)
: $builder->getModel()->newCollection();
return $this->paginator($results, $total, $perPage, $page, [
'path' => Paginator::resolveCurrentPath(),
'pageName' => $pageName,
]);
}
</code>Finally, use the custom paginator in code:
<code>Model::query()->staticPaginate($pageSize);
</code>By following these steps the Laravel application will generate clean pseudo‑static pagination URLs while still supporting normal query‑based pagination where needed.
php中文网 Courses
php中文网's platform for the latest courses and technical articles, helping PHP learners advance quickly.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.