CodeIgniter 4 ページネーション — Bootstrap 5によるカスタムスタイリング
原題: CodeIgniter 4 Pagination — Custom Styling with Bootstrap 5
分析結果
- カテゴリ
- エネルギー
- 重要度
- 58
- トレンドスコア
- 20
- 要約
- この記事では、CodeIgniter 4のページネーションをBootstrap 5を使用してカスタマイズする方法について説明します。Bootstrapのスタイルを適用することで、ページネーションの見た目を改善し、ユーザーにとって使いやすいインターフェースを提供します。具体的なコード例や設定手順を通じて、開発者が簡単に実装できるように解説しています。
- キーワード
Difficulty: Beginner–Intermediate | Read time: 10 min | Framework: CodeIgniter 4 The Problem with Default CI4 Pagination CodeIgniter 4 has built-in pagination — but the default output looks nothing like Bootstrap 5. You get plain links with no styling, no active states, no prev/next arrows. In every real project I've worked on, I end up customizing it. This tutorial shows you exactly how — from basic setup to a fully styled Bootstrap 5 paginator with AJAX support. What we're building: A paginated list of records styled with Bootstrap 5, with custom prev/next buttons, active page highlighting, and optional AJAX loading. Basic Setup First Let's say you have a products table and want to paginate results. 1. The Model <?php // app/Models/ProductModel.php namespace App\Models ; use CodeIgniter\Model ; class ProductModel extends Model { protected $table = 'products' ; protected $primaryKey = 'id' ; protected $allowedFields = [ 'name' , 'price' , 'category' , 'created_at' ]; public function getProducts ( int $perPage = 10 ): array { return $this -> paginate ( $perPage ); } } 2. The Controller <?php // app/Controllers/Products.php namespace App\Controllers ; use App\Models\ProductModel ; class Products extends BaseController { public function index (): string { $model = new ProductModel (); $perPage = 10 ; $data [ 'products' ] = $model -> getProducts ( $perPage ); $data [ 'pager' ] = $model -> pager ; $data [ 'perPage' ] = $perPage ; return view ( 'products/index' , $data ); } } 3. Basic View (before styling) <!-- app/Views/products/index.php --> <?php foreach ( $products as $product ) : ?> <div> <?= esc ( $product [ 'name' ]) ?> — ₹ <?= $product [ 'price' ] ?> </div> <?php endforeach ; ?> <!-- Default pagination (unstyled) --> <?= $pager -> links () ?> This works — but looks terrible. Let's fix that. Custom Bootstrap 5 Pagination Template CI4 lets you create a custom pagination template. This is the proper way to style it. Step 1 — Create the template file <!-- app/Views/pager/bootstrap_5.php --> <?php $pager -> setSurroundCount ( 2 ) ?> <nav aria-label= "Page navigation" > <ul class= "pagination justify-content-center mb-0" > <?php if ( $pager -> hasPreviousPage ()) : ?> <li class= "page-item" > <a class= "page-link" href= " <?= $pager -> getPreviousPageURI () ?> " aria-label= "Previous" > <span aria-hidden= "true" > « </span> </a> </li> <?php else : ?> <li class= "page-item disabled" > <span class= "page-link" > « </span> </li> <?php endif ?> <?php foreach ( $pager -> links () as $link ) : ?> <li class= "page-item <?= $link [ 'active' ] ? 'active' : '' ?> " > <?php if ( $link [ 'active' ]) : ?> <span class= "page-link" > <?= $link [ 'title' ] ?> <span class= "visually-hidden" > (current) </span> </span> <?php else : ?> <a class= "page-link" href= " <?= $link [ 'uri' ] ?> " > <?= $link [ 'title' ] ?> </a> <?php endif ?> </li> <?php endforeach ?> <?php if ( $pager -> hasNextPage ()) : ?> <li class= "page-item" > <a class= "page-link" href= " <?= $pager -> getNextPageURI () ?> " aria-label= "Next" > <span aria-hidden= "true" > » </span> </a> </li> <?php else : ?> <li class= "page-item disabled" > <span class= "page-link" > » </span> </li> <?php endif ?> </ul> </nav> Step 2 — Register the template in config // app/Config/Pager.php public array $templates = [ 'default_full' => 'CodeIgniter\Pager\Views\default_full' , 'default_simple' => 'CodeIgniter\Pager\Views\default_simple' , 'bootstrap_5' => 'App\Views\pager\bootstrap_5' , // <-- add this line ]; Step 3 — Use it in your view <!-- Now use your custom template --> <?= $pager -> links ( 'default' , 'bootstrap_5' ) ?> That's it — fully Bootstrap 5 styled pagination! ✅ Extra Styling — Make It Look Even Better Add this CSS to make the active page and hover states pop: /* Custom pagination styling */ .pagination .page-link { color : #6610f2 ; border-color : #dee2e6 ; padding : 8px 14px ; font-size : 14px ; transition : all 0.2s ease ; } .pagination .page-item.active .page-link { background-color : #6610f2 ; border-color : #6610f2 ; color : #fff ; } .pagination .page-link :hover { background-color : #f0ebff ; color : #6610f2 ; border-color : #6610f2 ; } .pagination .page-item.disabled .page-link { color : #adb5bd ; pointer-events : none ; } Show Record Count (Very Useful in Real Projects) Users want to know "Showing 1–10 of 154 records". Here's how: // In your controller — add these to $data $data [ 'total' ] = $model -> countAllResults (); $data [ 'currentPage' ] = $model -> pager -> getCurrentPage (); $data [ 'perPage' ] = $perPage ; <!-- In your view --> <?php $start = (( $currentPage - 1 ) * $perPage ) + 1 ; $end = min ( $currentPage * $perPage , $total ); ?> <div class= "d-flex justify-content-between align-items-center mb-3" > <small class= "text-muted" > Showing <?= $start ?> – <?= $end ?> of <?= $total ?> records </small> <?= $pager -> links ( 'default' , 'bootstrap_5' ) ?> </div> Output: Showing 1–10 of 154 records with pagination on the right. Clean and professional! AJAX Pagination (No Page Reload) For a smoother experience, load pages via AJAX: <!-- In your view --> <div id= "products-wrapper" > <?= view ( 'products/_table' , [ 'products' => $products ]) ?> </div> <div id= "pagination-wrapper" > <?= $pager -> links ( 'default' , 'bootstrap_5' ) ?> </div> <script> $ ( document ). on ( ' click ' , ' #pagination-wrapper .page-link ' , function ( e ) { e . preventDefault (); const url = $ ( this ). attr ( ' href ' ); if ( ! url || url === ' # ' ) return ; $ . get ( url , function ( response ) { const html = $ ( response ); $ ( ' #products-wrapper ' ). html ( html . find ( ' #products-wrapper ' ). html ()); $ ( ' #pagination-wrapper ' ). html ( html . find ( ' #pagination-wrapper ' ). html ()); // Scroll to top of table smoothly $ ( ' html, body ' ). animate ({ scrollTop : $ ( ' #products-wrapper ' ). offset (). top - 80 }, 300 ); }); }); </script> Common Pitfalls ⚠️ 1. Pagination not working with WHERE filters If you apply filters before paginate() , always use $model->where() before calling it: // WRONG — filter applied after, pagination counts wrong $data [ 'products' ] = $model -> paginate ( $perPage ); $model -> where ( 'category' , 'electronics' ); // CORRECT — filter first, then paginate $data [ 'products' ] = $model -> where ( 'category' , $category ) -> paginate ( $perPage ); $data [ 'pager' ] = $model -> pager ; ⚠️ 2. Template not found error Make sure the path in Pager.php config matches exactly: 'bootstrap_5' => 'App\Views\pager\bootstrap_5' // File must be at: app/Views/pager/bootstrap_5.php ⚠️ 3. Page resets to 1 on form submit When using search + pagination together, pass the current page in your form: <input type= "hidden" name= "page" value= "<?= $currentPage ?>" > And in controller: $page = $this -> request -> getGet ( 'page' ) ?? 1 ; $data [ 'products' ] = $model -> where ( 'name LIKE' , "% { $search } %" ) -> paginate ( $perPage , 'default' , $page ); Full Working Example — Products Page Here's everything together in one clean view: <!-- app/Views/products/index.php --> <div class= "container py-4" > <div class= "d-flex justify-content-between align-items-center mb-4" > <h4 class= "mb-0" > Products </h4> <small class= "text-muted" > Showing <?= $start ?> – <?= $end ?> of <?= $total ?> records </small> </div> <div class= "table-responsive" id= "products-wrapper" > <table class= "table table-hover align-middle" > <thead class= "table-light" > <tr> <th> # </th> <th> Product Name </th> <th> Category </th> <th> Price </th> </tr> </thead> <tbody> <?php foreach ( $products as $p ) : ?> <tr> <td> <?= $p [ 'id' ] ?> </td> <td> <?= esc ( $p [ 'name' ]) ?> </td> <td><span class= "badge bg-secondary" > <?= esc ( $p [ 'category' ]) ?> </span></td> <td> ₹ <?= number_format ( $p [ 'price' ], 2 ) ?> </td> </tr> <?php endforeach ; ?> </tbody> </table> </div> <div id= "pagination-wrapper" class= "mt-3" > <?= $pager -> links ( 'default' , 'bootstrap_5' ) ?> </div> </div> What to Read Next CodeIgniter 4 DataTables Server-Side Processing — for large datasets with search/sort CodeIgniter 4 + jQuery AJAX CRUD — full AJAX without page reload Dynamic Report with Date Range Filters in CodeIgniter — pagination with complex filters Conclusion CI4's pagination is powerful once you know how to configure it. A custom Bootstrap 5 template + the record count display makes your app look polished and professional — exactly what clients expect. Follow me for more CodeIgniter production tutorials — 3 new articles every week. 🙌 Senior PHP Developer · 12+ years building production systems on CodeIgniter, Laravel & WordPress Difficulty: Beginner–Intermediate | Read time: 10 min | Framework: CodeIgniter 4 The Problem with Default CI4 Pagination CodeIgniter 4 has built-in pagination — but the default output looks nothing like Bootstrap 5. You get plain links with no styling, no active states, no prev/next arrows. In every real project I've worked on, I end up customizing it. This tutorial shows you exactly how — from basic setup to a fully styled Bootstrap 5 paginator with AJAX support. What we're building: A paginated list of records styled with Bootstrap 5, with custom prev/next buttons, active page highlighting, and optional AJAX loading. Basic Setup First Let's say you have a products table and want to paginate results. 1. The Model <?php // app/Models/ProductModel.php namespace App\Models ; use CodeIgniter\Model ; class ProductModel extends Model { protected $table = 'products' ; protected $primaryKey = 'id' ; protected $allowedFields = [ 'name' , 'price' , 'category' , 'created_at' ]; public function getProducts ( int $perPage = 10 ): array { return $this -> paginate ( $perPage ); } } 2. The Controller <?php // app/Controllers/Products.php namespace App\Controllers ; use App\Models\ProductModel ; class Products extends BaseController { public function index (): string { $model = new ProductModel (); $perPage = 10 ; $data [ 'products' ] = $model -> getProduct