管理画面のテーブル件数に応じて、ページングする

WordPress

前回まで作った管理テーブルに対し、データ件数が増えてきた場合を想定して、ページング処理を入れます。

前回までの、テーブル一覧部分のコードは以下のとおりです。

	/**
	 * 初期表示
	 */
	function disp()
	{
		//データ一覧
		echo <<< EOL
<form action="" method="post">

	<h2>データ一覧</h2>
	<input type='submit' name='submit[regist]' class='button-primary' value='新規登録' />

	<div class="wrap">

	<table class="wp-list-table widefat striped posts">
		<tr>
			<th nowrap>ID</th>
			<th nowrap>名前</th>
			<th nowrap>登録日時</th>
			<th nowrap>詳細</th>
			<th nowrap>編集</th>
		</tr>
EOL;

		global $wpdb;

		$tbl_name = $wpdb->prefix . 'sample_mst';
		$sql = "SELECT * FROM {$tbl_name} ORDER BY id;";
		$rows = $wpdb->get_results($sql);

		foreach($rows as $row) {
			echo "<tr>";
			echo "<td>" . $row->id . "</td>";
			echo "<td>" . $row->sample_name . "</td>";
			echo "<td>" . $row->create_date . "</td>";
			echo "<td>";
			echo "<input type='submit' name='submit[detail][" . $row->id . "]'";
			echo " class='button-primary' value='詳細' />";
			echo "</td>";
			echo "<td>";
			echo "<input type='submit' name='submit[edit][" . $row->id . "]'";
			echo " class='button-primary' value='編集' />";
			echo "</td>";
			echo "</tr>";
		}
		echo "</table>";
		echo "</div>";
		echo "</form>";
	}

このコードに対し、ページ処理を入れていきます。

まず、現在のページ番号をGETパラメータで受け渡す為、パラメータ取得用の変数を用意し、取得します。

$pageid = filter_input(INPUT_GET, 'pageid');

次に、1ページあたり、何件表示して次のページに移るのか、上限を決定します。

//1ページあたりの件数
$limit = 10;

次に、対象となるデータの総件数を取得します

//DBオブジェクトを用意
global $wpdb;

//全件数取得
$tbl_name = $wpdb->prefix . 'sample_mst';
$sql = "SELECT count(*) AS CNT FROM {$tbl_name}";
$rows = $wpdb->get_results($sql);
$recordcount = $rows[0]->CNT;

ここで、$recordcountという変数に総件数が格納されます。

次に、ページ遷移した時に、データベースからオフセットした値を取得する為に、SQL用にoffset値を決定します。

//offsetの値を決定
$offset = $pageid * $limit;

最後に、データベースにクエリを発行し、データを取得します。
ここのタイミングではlimit件数(10件ごと)にデータを区切って取得しています。

//offset と limitによる画面表示用のデータ取得
$sql = "SELECT * FROM {$tbl_name} ORDER BY id limit {$offset}, {$limit};";

//通常の取得方法(SQL実行結果を、オブジェクトとして取得)
$rows = $wpdb->get_results($sql);

次にページ処理用のメソッドと、それに応じたパラメータを書いておきます。

$args = array(
	'label' => __('Per Page'),
	'default' => 10,
	'option' => 'disp'
);
$page_html = self::pagination($recordcount);

paginationというメソッド名は、function disp()の外側の任意の箇所に記述します。

function pagination($recordcount)
{
	$count = $recordcount;
	$limit = 10;

	//レコード総数がゼロのときは何も出力しない
	if (0 === $count) {
		return '';
	}

	//現在表示中のページ番号(ゼロスタート)
	$intCurrentPage = self::getCurrentPage();

	//ページの最大数
	$intMaxpage = ceil($count / $limit);

	//現在ページの前後3ページを出力
	$intStartpage = (2 < $intCurrentPage) ? $intCurrentPage - 3 : 0;
	$intEndpage = (($intStartpage + 7) < $intMaxpage) ? $intStartpage + 7 : $intMaxpage;

	//url組み立て
	$urlparams = filter_input_array(INPUT_GET);

	$items = [];

	//ページURLの生成
	//最初
	$urlparams['page'] = filter_input(INPUT_GET, 'page');
	$urlparams['pageid'] = 0;
	$items[] = sprintf('<span><a href="?%s">%s</a></span>'
		, http_build_query($urlparams)
		, '最初'
	);

	//表示中のページが先頭ではない時
	if (0 < $intCurrentPage) {
		$urlparams['pageid'] = $intCurrentPage - 1;
		$items[] = sprintf('<span><a href="?%s">%s</a></span>'
			, http_build_query($urlparams)
			, '前へ'
		);
	}

	for ($i = $intStartpage; $i < $intEndpage; $i++) {
		$urlparams['pageid'] = $i;
		$items[] = sprintf('<span%s><a href="?%s">%s</a></span>'
			, ($intCurrentPage == $i) ? ' class="current"' : ''
			, http_build_query($urlparams)
			, $i + 1
		);
	}

	//表示中のページが最後ではない時
	if ($intCurrentPage < ($intMaxpage - 1)) {
		$urlparams['pageid'] = $intCurrentPage + 1;
		$items[] = sprintf('<span><a href="?%s">%s</a></span>'
			, http_build_query($urlparams)
			, '次へ'
		);
	}

	//最後
	$urlparams['pageid'] = $intMaxpage - 1;
	$items[] = sprintf('<span><a href="?%s">%s</a></span>'
		, http_build_query($urlparams)
		, '最後'
	);

	return $items;
}

最終的に、$page_htmlという変数に、ページング出力用の情報が入るので、それを画面出力用に整形して、出力します。

//ページ部分の表示
echo "<div class='admin_pagination'>";
echo "<ul>";
foreach ($page_html as $key => $value) {
	echo "<li>" . $value . "</li>";
}
echo "</ul>";

このままでは、文字列のみのページ表示になるので、cssでスタイルを調整します。

/* ページング処理 */
.admin_pagination ul li {
	display: inline-block;
	padding: 0px 1px 0px 1px;
	margin: 0px 3px 0px 3px;
	background-color: #DBDBDB;
}
.admin_pagination ul li .current a{
	color: #FFFFFF;
	background-color: #666666;
}
.admin_pagination ul a {
	display: block;
	padding: 8px 10px 8px 10px;
}

これで、テーブルに関連するページング処理の表示ができました。

出力結果は以下のようになります。

試しに3ページ目にアクセスする。

このように表示されます。

作っている最中に、気づきが遅かった部分がありました。
$wpdbのオブジェクトに対し、get_resultsメソッドを使ったSQL実行で、
offset、limitの処理を書いた場合、一般的なSQLの書き方では、
思うような抽出結果が得られませんでした。

SELECT * FROM テーブル名 OFFSET 10 LIMIT 5;

などと書くのはNGで、

SELECT * FROM テーブル名 LIMIT 10, 5;

のように書かないと、想定した出力結果が得られませんでした。
wpdbのget_resultsの仕様ページを見たのですが、明確な記載はありませんでした。
気づくまでに時間がかかってしまいました。

(2022/07/21 追記)
下記の箇所に不具合がありましたので、修正したコードに更新しました。
if文の「$intMaxpage」について、ページ遷移の仕方によっては不正な条件判定でしたので「($intMaxpage – 1)」という調整をしています。
根本的な対処とは言えませんが、訂正いたします。

■変更前

	//表示中のページが最後ではない時
	if ($intCurrentPage < $intMaxpage) {
		$urlparams['pageid'] = $intCurrentPage + 1;
		$items[] = sprintf('<span><a href="?%s">%s</a></span>'
			, http_build_query($urlparams)
			, '次へ'
		);
	}

■変更後

	//表示中のページが最後ではない時
	if ($intCurrentPage < ($intMaxpage - 1)) {
		$urlparams['pageid'] = $intCurrentPage + 1;
		$items[] = sprintf('<span><a href="?%s">%s</a></span>'
			, http_build_query($urlparams)
			, '次へ'
		);
	}

(2022/07/22 追記)
記載したソースコードの中で呼ばれているメソッド「getCurrentPage」の中身については、下記のメソッドになります。

/**
 * 現在のページ番号を取得する
 * @return int
 */
function getCurrentPage()
{
    $pageid = esc_attr($_REQUEST["pageid"]);
    return $pageid;
}

管理画面のテーブル件数に応じて、ページングする” への3件のフィードバック

  1. お疲れ様です。

    //現在表示中のページ番号(ゼロスタート)
    $intCurrentPage = self::getCurrentPage();

    ↑上記のgetCurrentPage()クラスメンバーメソッドの中身をしりたいです。

    ※ 今その行でエラーになっております。

  2. ハン・スウェーさん

    コメントいただきありがとうございます。

    上記の「getCurrentPage()メソッド」についてはブログ記事内に記載しておりませんでした。
    詳しくは、以下のようになります。

    	/**
    	 * 現在のページ番号を取得する
    	 * @return int
    	 */
    	function getCurrentPage()
    	{
    		$pageid = esc_attr($_REQUEST["pageid"]);
    		return $pageid;
    	}
    

    このメソッドを「function pagination($recordcount)」の前または後に記述すると動作するかと思います。
    ご確認をお願いします。

  3. ご回答、どうもありがとうございました。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です