本文へ移動
Laravel Tips

ページ送り(ページネーション)

データを1ページ分ずつに分けて表示するページ送り(ページネーション)の、使い方・リンクの表示・カーソル方式・見た目の変え方を説明します。

ページ送り(ページネーション)は、たくさんのデータを、1ページに少しずつ表示して、「次へ」「前へ」やページ番号のリンクで移れるようにするしくみです。本の目次を、何ページかに分けて見せるようなものです。

Laravel のページ送りは、クエリビルダ(SQL を書かずに、メソッドをつないでデータベースに問い合わせるしくみ)と、Eloquent(データベースの表を、PHP から扱いやすくしたモデルのしくみ)の両方に組みこまれています。設定をしなくても、すぐ使えます。

ページ送りが作る HTML は、はじめは Tailwind CSS(CSS の道具)に合わせてあります。Bootstrap(別の CSS の道具)に合わせることもできます。

Tailwind と使うとき#

Laravel が用意したページ送りの画面を Tailwind 4.x で使うなら、準備は要りません。アプリの resources/css/app.css に、ページ送りの画面を Tailwind に読ませる @source の行が、はじめから書いてあります。

css
@import 'tailwindcss';

@source '../../vendor/laravel/framework/src/Illuminate/Pagination/resources/views/*.blade.php';

基本の使い方#

クエリビルダの結果をページに分ける#

ページに分ける方法はいくつかあります。いちばんかんたんなのは、クエリビルダか Eloquent の問い合わせで、paginate メソッドを使うことです。paginate は、いま見ているページに合わせて、問い合わせの「limit」(取り出す数)と「offset」(読み飛ばす数)を、自動で決めます。

いま何ページ目かは、リクエストのクエリ文字列(URL の ? のあとの部分)の page から分かります。この値は Laravel が自動で見つけ、ページ送りが作るリンクにも自動で入ります。

次の例では、paginate に、1ページに出す数を渡しています。ここでは 15 件です。

php
<?php

namespace App\Http\Controllers;

use Illuminate\Support\Facades\DB;
use Illuminate\View\View;

class UserController extends Controller
{
    /**
     * Show all application users.
     */
    public function index(): View
    {
        return view('user.index', [
            'users' => DB::table('users')->paginate(15)
        ]);
    }
}

かんたんなページ送り#

paginate は、データを取る前に、条件に合う全部の件数を数えます。ページが全部で何ページあるかを、知るためです。でも、全部のページ数を画面に出さないなら、この件数を数える問い合わせは、無駄になります。

「次へ」と「前へ」のリンクだけでよいときは、simplePaginate を使うと、1回の問い合わせで済み、効率がよくなります。

php
$users = DB::table('users')->simplePaginate(15);

Eloquent の結果をページに分ける#

Eloquent の問い合わせも、ページに分けられます。次の例では、App\Models\User モデルを、1ページ 15 件で分けています。書き方は、クエリビルダとほとんど同じです。

php
use App\Models\User;

$users = User::paginate(15);

where など、ほかの条件をつけたあとでも、paginate を呼べます。

php
$users = User::where('votes', '>', 100)->paginate(15);

Eloquent でも、simplePaginate が使えます。

php
$users = User::where('votes', '>', 100)->simplePaginate(15);

cursorPaginate で、カーソル方式(次の節)のページ送りもできます。

php
$users = User::where('votes', '>', 100)->cursorPaginate(15);

1つの画面に、ページ送りが複数あるとき#

1つの画面に、ページ送りを2つ出したいことがあります。でも、2つとも、クエリ文字列の page にいまのページを入れると、ぶつかります。ぶつからないように、paginate・simplePaginate・cursorPaginate の3つ目の引数に、使うクエリ文字列の名前を渡せます。

php
use App\Models\User;

$users = User::where('votes', '>', 100)->paginate(
    $perPage = 15, $columns = ['*'], $pageName = 'users'
);
メソッド 説明
paginate ページ番号のリンクが出せる。全部の件数を数える
simplePaginate 「次へ」と「前へ」だけ。件数を数えないので効率がよい
cursorPaginate カーソル方式。「次へ」と「前へ」だけ。大量のデータ向き

カーソル方式のページ送り#

paginate と simplePaginate は、SQL の「offset」(読み飛ばし)を使って問い合わせます。カーソル方式は、ちがいます。並べ替えた列の値を比べる「where」(条件)を作って問い合わせます。Laravel のページ送りの中で、いちばんデータベースの負担が少ない方法です。データが多いときや、「無限スクロール」(下へ動かすと続きが出る画面)に、向いています。

offset の方式では、ページ番号が、リンクのクエリ文字列に入ります。カーソル方式では、「カーソル」という文字が入ります。カーソルは、次の問い合わせをどこから始めるか、どちらの向きに進むかを、短い文字に変えて(エンコードして)まとめたものです。

text
http://localhost/users?cursor=eyJpZCI6MTUsIl9wb2ludHNUb05leHRJdGVtcyI6dHJ1ZX0

クエリビルダの cursorPaginate メソッドで、カーソル方式のページ送りを作れます。Illuminate\Pagination\CursorPaginator が返ります。

php
$users = DB::table('users')->orderBy('id')->cursorPaginate(15);

作ったあとは、paginate と simplePaginate のときと同じに、結果を表示(下の「ページ送りの結果を表示する」の節)できます。カーソル方式のメソッドは、このページの最後の表にあります。

注意

カーソル方式を使うには、問い合わせに「order by」(並べ替え)が必要です。また、並べ替えに使う列は、ページに分ける表の列でなければなりません。

カーソルと offset のちがい#

2つの方式のちがいを、SQL で見てみます。次の2つは、どちらも、users の表を id 順に並べたときの「2ページ目」を取り出します。

sql
# Offset Pagination...
select * from users order by id asc limit 15 offset 15;

# Cursor Pagination...
select * from users where id > 15 order by id asc limit 15;

カーソル方式には、offset の方式にない、よい点があります。

  • データが多いとき、並べ替えの列に索引(検索を速くするしくみ)があれば、速くなる。offset は、それまでの分を、全部読み飛ばしながら探すため
  • 書きこみが多いデータでは、offset の方式だと、ユーザーが見ているページの内容が、追加や削除で変わったときに、行が抜けたり、重なって出たりすることがある

一方、カーソル方式には、次の制限があります。

  • simplePaginate と同じく、「次へ」と「前へ」のリンクだけで、ページ番号のリンクは作れない
  • 重ならない列を、少なくとも1つ使った並べ替えが必要(重ならない列の組み合わせでもよい)。null を含む列は使えない
  • 「order by」の式は、別名を付けて「select」にも加えたときだけ使える
  • 引数を持つ式は使えない

ページ送りを手で作る#

データベースから取ったものではなく、プログラムの中にすでにある配列で、ページ送りを手で作りたいことがあります。必要に応じて、Illuminate\Pagination\Paginator・Illuminate\Pagination\LengthAwarePaginator・Illuminate\Pagination\CursorPaginator のどれかを作ります。

Paginator と CursorPaginator は、全部の件数を知る必要がありません。その代わり、最後のページの番号を取り出すメソッドがありません。LengthAwarePaginator は、ほとんど同じ引数ですが、全部の件数が要ります。

つまり、クエリビルダの simplePaginate が Paginator、cursorPaginate が CursorPaginator、paginate が LengthAwarePaginator に対応します。

注意

手でページ送りを作るときは、渡す配列を、自分で「切り分け」る必要があります。やり方が分からなければ、PHP の array_slice 関数を調べてください。

リンクの URL を変える#

はじめは、ページ送りが作るリンクは、いまのリクエストの URI(/users のような、URL の中で場所を表す部分)と同じになります。withPath メソッドで、リンクに使う URI を変えられます。たとえば、http://example.com/admin/users?page=N のようなリンクにしたいなら、withPath に /admin/users を渡します。

php
use App\Models\User;

Route::get('/users', function () {
    $users = User::paginate(15);

    $users->withPath('/admin/users');

    // ...
});

クエリ文字列を足す#

appends メソッドで、ページ送りのリンクのクエリ文字列に、値を足せます。たとえば、全部のリンクに sort=votes を足すには、次のように書きます。

php
use App\Models\User;

Route::get('/users', function () {
    $users = User::paginate(15);

    $users->appends(['sort' => 'votes']);

    // ...
});

いまのリクエストのクエリ文字列を、全部足したいときは、withQueryString を使います。

php
$users = User::paginate(15)->withQueryString();

ハッシュ(#)を足す#

リンクの最後に、ハッシュ(# のあとの、ページの中の場所を示す部分)を足したいときは、fragment メソッドを使います。たとえば、全部のリンクの最後に #users を足すには、次のように書きます。

php
$users = User::paginate(15)->fragment('users');
メソッド 説明
withPath リンクに使う URI を変える
appends リンクのクエリ文字列に、決めた値を足す
withQueryString いまのリクエストのクエリ文字列を、全部リンクに足す
fragment リンクの最後に、ハッシュを足す

ページ送りの結果を表示する#

paginate を呼ぶと Illuminate\Pagination\LengthAwarePaginator、simplePaginate を呼ぶと Illuminate\Pagination\Paginator、cursorPaginate を呼ぶと Illuminate\Pagination\CursorPaginator が返ります。

これらには、結果のようす(全部で何件か、いま何ページ目か、など)を知るメソッドがあります。また、配列と同じように @foreach でくり返せます。取り出した結果の表示と、ページのリンクの表示は、Blade で書けます。

blade
<div class="container">
    @foreach ($users as $user)
        {{ $user->name }}
    @endforeach
</div>

{{ $users->links() }}

links メソッドは、ほかのページへのリンクを表示します。リンクには、正しい page のクエリ文字列が、すでに入っています。links が作る HTML は、Tailwind CSS に合わせてあります。

リンクの数を変える#

ページ送りのリンクには、いまのページの番号と、その前後 3 ページずつのリンクが出ます。onEachSide メソッドで、いまのページの両側に出すリンクの数を変えられます。

blade
{{ $users->onEachSide(5)->links() }}

結果を JSON にする#

ページ送りのクラスは、Illuminate\Contracts\Support\Jsonable というインターフェース(クラスが持つべきメソッドの決まり)に従っていて、toJson メソッドを持っています。そのため、結果をかんたんに JSON(データを文字で表す形式)にできます。ルートやコントローラーから、ページ送りをそのまま返しても、JSON になります。

php
use App\Models\User;

Route::get('/users', function () {
    return User::paginate();
});

JSON には、total・current_page・last_page など、ページ送りの情報(メタ情報)が入ります。結果の行は、data というキーの中にあります。ルートからページ送りを返したときの JSON の例です。

json
{
   "total": 50,
   "per_page": 15,
   "current_page": 1,
   "last_page": 4,
   "first_page_url": "http://laravel.app?page=1",
   "last_page_url": "http://laravel.app?page=4",
   "next_page_url": "http://laravel.app?page=2",
   "prev_page_url": null,
   "path": "http://laravel.app",
   "from": 1,
   "to": 15,
   "data":[
        {
            // Record...
        },
        {
            // Record...
        }
   ]
}

ページ送りの見た目を変える#

リンクを作る画面(ビュー)は、はじめは Tailwind CSS に合わせてあります。Tailwind を使わないなら、自分の画面を作れます。ページ送りの links メソッドの1つ目の引数に、ビューの名前を渡します。

blade
{{ $paginator->links('view.name') }}

<!-- Passing additional data to the view... -->
{{ $paginator->links('view.name', ['foo' => 'bar']) }}

いちばんかんたんな方法は、vendor:publish コマンドで、ビューを resources/views/vendor へ取り出して、直すことです。

bash
php artisan vendor:publish --tag=laravel-pagination

このコマンドは、ビューを、アプリの resources/views/vendor/pagination に置きます。その中の tailwind.blade.php が、はじめのページ送りの画面です。このファイルを直せば、ページ送りの HTML を変えられます。

別のファイルを、はじめの画面にしたいときは、App\Providers\AppServiceProvider の boot メソッドで、defaultView と defaultSimpleView を呼びます。

php
<?php

namespace App\Providers;

use Illuminate\Pagination\Paginator;
use Illuminate\Support\ServiceProvider;

class AppServiceProvider extends ServiceProvider
{
    /**
     * Bootstrap any application services.
     */
    public function boot(): void
    {
        Paginator::defaultView('view-name');

        Paginator::defaultSimpleView('view-name');
    }
}

Bootstrap を使う#

Laravel には、Bootstrap CSS に合わせたページ送りの画面も入っています。はじめの Tailwind の画面の代わりに使うには、App\Providers\AppServiceProvider の boot メソッドで、useBootstrapFour か useBootstrapFive を呼びます。

php
use Illuminate\Pagination\Paginator;

/**
 * Bootstrap any application services.
 */
public function boot(): void
{
    Paginator::useBootstrapFive();
    Paginator::useBootstrapFour();
}
メソッド 説明
defaultView はじめのページ送りの画面を、別のビューにする
defaultSimpleView かんたんなページ送り用の、はじめの画面を、別のビューにする
useBootstrapFive Bootstrap 5 用の画面を使う
useBootstrapFour Bootstrap 4 用の画面を使う

Paginator と LengthAwarePaginator のメソッド#

ページ送りのオブジェクト($paginator)には、次のメソッドがあります。$paginator->count() のように呼びます。

メソッド 説明
count() いまのページの件数
currentPage() いまのページの番号
firstItem() 結果の中で、最初の行の番号
getOptions() ページ送りの設定を取り出す
getUrlRange($start, $end) ページの URL を、範囲でまとめて作る
hasPages() 複数のページに分けるほど、行があるか
hasMorePages() データの置き場に、まだ続きがあるか
items() いまのページの行を取り出す
lastItem() 結果の中で、最後の行の番号
lastPage() 最後のページの番号(simplePaginate では使えない)
nextPageUrl() 次のページの URL
onFirstPage() 最初のページにいるか
onLastPage() 最後のページにいるか
perPage() 1ページに出す件数
previousPageUrl() 前のページの URL
total() 条件に合う、全部の件数(simplePaginate では使えない)
url($page) 指定したページの URL
getPageName() ページ番号を入れる、クエリ文字列の名前を取り出す
setPageName($name) ページ番号を入れる、クエリ文字列の名前を決める
through($callback) 関数で、1つ1つの行を変える

Cursor Paginator のメソッド#

カーソル方式のページ送りのオブジェクトには、次のメソッドがあります。

メソッド 説明
count() いまのページの件数
cursor() いまのカーソルを取り出す
getOptions() ページ送りの設定を取り出す
hasPages() 複数のページに分けるほど、行があるか
hasMorePages() データの置き場に、まだ続きがあるか
getCursorName() カーソルを入れる、クエリ文字列の名前を取り出す
items() いまのページの行を取り出す
nextCursor() 次の行の組のカーソルを取り出す
nextPageUrl() 次のページの URL
onFirstPage() 最初のページにいるか
onLastPage() 最後のページにいるか
perPage() 1ページに出す件数
previousCursor() 前の行の組のカーソルを取り出す
previousPageUrl() 前のページの URL
setCursorName() カーソルを入れる、クエリ文字列の名前を決める
url($cursor) 指定したカーソルの URL

関連するページ#

公式ドキュメント(英語)

2026年10月5日時点の内容をもとに、日本語でまとめています。

ページの一覧