📌

PHPでページング(ページネーション)を作る(備忘録)

2021/02/11に公開

目次

  1. ページング(ページネーション)とは
  2. 完成図
  3. 「戻る」を作る
  4. ページ番号を作る
  5. 「進む」を作る
  6. ○件目と表示するには
  7. 終わりに

ページング(ページネーション)とは

ページネーションとは、日本語で『ページ送り』『ページ割り』と呼ばれる機能のことで、内容量が多いコンテンツを分割して表示するときに使用されます。
ブログやフリマアプリなどでよく見る「<< 1 2 3 4 5 >>」みたいに表示されているあれ。
あれって便利なんですけど、自分で作るのはとても大変だったので備忘録的に書いてみます。
一応ちゃんと動きましたが、これ違うとかもっとこうしたらいいというのがあったら教えてください。

完成図

こんな感じです


「<<」もしくは「>>」を押して次のページに行ったり前のページに戻ったりします。
現在は最初のページなので「<<」は薄い灰色になってクリックすることができないようになっています。


常時現在のページを含む5つの数字が並ぶようになっています。
数字をクリックしたらその数字のページに飛ぶようになっています。
薄い灰色が背景になっている数字が現在のページです。現在ページはクリックできないようにしています。


最後のページにいくと「>>」は薄い色となりクリックできないようになります。
今は登録データが80件あるので、「80件中76 - 80件目を表示」となっていますが、これが79件だったら「76-79件目を表示」となります。

index_controller.php
//SQL文を変数にいれる。$count_sqlはデータの件数取得に使うための変数。
$count_sql = 'SELECT COUNT(*) as cnt FROM テーブル名';

//ページ数を取得する。GETでページが渡ってこなかった時(最初のページ)のときは$pageに1を格納する。
if(isset($_GET['page']) && is_numeric($_GET['page'])) {
  $page = $_GET['page'];
} else {
  $page = 1;
}

//最大ページ数を取得する。
//5件ずつ表示させているので、$count['cnt']に入っている件数を5で割って小数点は切りあげると最大ページ数になる。
$counts = $database -> query($count_sql);
$count = $counts -> fetch(PDO::FETCH_ASSOC);
$max_page = ceil($count['cnt'] / 5);

「戻る」を作る

index.php
<div class="pagination">
<?php if ($page >= 2): ?>
            <a href="index.php?page=<?php echo($page - 1); ?>" class="page_feed">&laquo;</a>
        <?php else : ;?>
            <span class="first_last_page">&laquo;</span>
        <?php endif; ?>

現在のページが2以上だったら戻るリンクをつける。そうでなければリンクはつけない。
「戻る」ので現在のページ($page)から1を引いている。

cssはこんな感じでしました。flexで横並びにします

stylesheet.css
a:link {text-decoration:none }
a.page_number:visited {color: black; text-decoration:none }
.pagination {
  display: flex;
  justify-content: center;
  margin: 15px;
}
.page_feed {
  width: 30px;
  margin: 0 10px;
  padding: 5px 10px;
  text-align: center;
  background: #b8b8b8;
  color: black;
}
.first_last_page {
  width: 30px;
  margin: 0 10px;
  padding: 5px 10px;
  text-align: center;
  background: #f0f0f0;
  color: black;
}

ページ番号を作る

index_controller.php
if($page == 1 || $page == $max_page) {
    $range = 4;
} elseif ($page == 2 || $page == $max_page - 1) {
    $range = 3;
} else {
    $range = 2;
}

$rangeというのは表示させるページの範囲を指定するときに使います。

index.php
<?php for ($i = 1; $i <= $max_page; $i++) : ?>
   <?php if($i >= $page - $range && $i <= $page + $range) : ?>
       <?php if($i == $page) : ?>
           <span class="now_page_number"><?php echo $i; ?></span>
       <?php else: ?>
           <a href="?page=<?php echo $i; ?>" class="page_number"><?php echo $i; ?></a>
       <?php endif; ?>
   <?php endif; ?>
<?php endfor; ?>

ページ番号はforでループさせて作ります。1〜最大ページ数まで。
現在ページとページ番号が同じ時はクリックできないようにします。

CSSはこんな感じにしました

stylesheet.css
a:link {text-decoration:none }
a.page_number:visited {color: black; text-decoration:none }
.page_number {
  width: 30px;
  margin: 0 10px;
  padding: 5px;
  text-align: center;
  background: #b8b8b8;
  color: black;
}
.now_page_number {
  width: 30px;
  margin: 0 10px;
  padding: 5px;
  text-align: center;
  background: #f0f0f0;
  color: black;
  font-weight: bold;
}

「進む」を作る

index.php
    <?php if($page < $max_page) : ?>
        <a href="index.php?page=<?php echo($page + 1); ?>" class="page_feed">&raquo;</a>
    <?php else : ?>
        <span class="first_last_page">&raquo;</span>
    <?php endif; ?>
</div>

「進む」なので現在ページ数に+1にします。
現在ページが最大ページ数を超えると「進む」はクリックできなくなります。

○件目と表示するには

index.php
<p class="from_to"><?php echo $count['cnt']; ?>件中 <?php echo $from_record; ?> - <?php echo $to_record;?> 件目を表示</p>
index_controller.php
$from_record = ($page - 1) * 5 + 1;

if($page == $max_page && $count['cnt'] % 5 !== 0) {
    $to_record = ($page - 1) * 5 + $count['cnt'] % 5;
} else {
    $to_record = $page * 5;
}

$count['cnt']で全件数を取ってきます。

レコードは5件ずつ表示させているので、○ - △件目を表示は

page数
page1 1 5
page2 6 10
page3 11 15
page4 16 20

○は(現在ページ - 1) * 5 + 1で表示できます

△は現在ページに5を掛けると表示できます。
しかしそれだと78件しかデータがないのに76-80件目となり表示がおかしくなってしまうので、
その場合は現在ページから1引いて5をかけた数に、全件数を5で割ったあまりの数を足すと正しい数が出てくる

(例)最大件数が18件目の時は、18は4ページめにあたるので(4-1)*5=15に18%5=3を足すと18になる

終わりに

間違っていたら是非ご指摘をお願いします。
シンプルに見えてめちゃくちゃ考え方が難しかったです。

Discussion