Portfolio作成 ⑦ 管理画面 - 記事編集画面 & 編集(Update)/ 削除(Delete)機能実装編

作業内容
先に完成状態の共有から
記事一覧画面(posts.php)に「編集」ボタン と 「削除」ボタン を追加

「編集」ボタンから遷移できる記事編集画面(edit-post.php)を作成

「削除」ボタンから遷移できる記事削除画面(delete-post.php)を作成

では、作業手順をお伝えします。
記事編集画面の作成
編集(Update)機能実装
edit-post.php(記事編集画面)ファイルへ記事更新処理を追加で記述
動作確認(記事編集画面→編集→「更新」ボタンを押す→記事一覧画面へ戻される→記事一覧画面と記事編集画面で更新の反映を確認する)
削除(Delete)機能実装
delete-post.php(記事削除画面)ファイルの作成
delete-post.php(記事削除画面)ファイルへ記述
動作確認(記事一覧画面→記事削除画面→「削除」ボタンを押す→「更新」ボタンを押す→記事一覧画面へ戻される→記事一覧画面で更新の反映を確認する)
管理者の記事一覧画面を作成について詳しく知りたい方は、こちらの記事を是非ご一読ください。
記事編集画面の作成
posts.php(記事一覧画面)へ「編集」ボタンを設置
posts.php(記事一覧画面)へ「編集」ボタンを設置していきます。
<?php
require_once '../config/database.php';
$stmt = $pdo->query("
SELECT *
FROM posts
ORDER BY id DESC
");
$posts = $stmt->fetchAll();
?>
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>記事一覧</title>
</head>
<body>
<h1>記事一覧</h1>
<p>
<a href="new-post.php">新規投稿</a>
</p>
<table border="1" cellpadding="10">
<tr>
<th>ID</th>
<th>タイトル</th>
<th>投稿日</th>
</tr>
<?php foreach ($posts as $post): ?>
<tr>
<td><?= $post['id'] ?></td>
<td>
<?= htmlspecialchars($post['title'], ENT_QUOTES, 'UTF-8') ?>
</td>
<td><?= $post['created_at'] ?></td>
<td>
<a href="edit-post.php?id=<?= $post['id'] ?>">
編集
</a>
</td>
</tr>
<?php endforeach; ?>
</table>
</body>
</html>
href="edit-post.php"
編集ページへのリンクです。
id=<?= $post['id']
どの記事の編集画面か特定できないためidを受け渡し、edit-post.php 側で判別できるようにしています。
edit-post.php(記事編集画面)ファイルの作成
portfolio(個人開発環境)配下の admin(管理者画面)配下に edit-post.php(記事編集画面)ファイルの作成を行います。

portfolio/
│
├── index.php ← 記事一覧(フロント)
├── post.php ← 記事詳細(フロント)
├── header.php ← 共通ヘッダー
├── footer.php ← 共通フッター
├── style.css ← CSS
├── test-db.php ← DB接続テスト
├── test-posts.php ← 投稿取得テスト
│
├── config/
│ └── database.php ← PDO接続設定
│
└── admin/
└── index.php ← 管理トップ
├── posts.php ← 記事一覧(管理)
├── new-post.php ← 記事作成
├── edit-post.php ← 記事編集
└── delete-post.php ← 記事削除
edit-post.php(記事編集画面)ファイルへ記述
作成した edit-post.php(記事編集画面)へ記述していきます。
<?php
require_once '../config/database.php';
/*
|--------------------------------------------------------------------------
| ID取得
|--------------------------------------------------------------------------
*/
$id = $_GET['id'] ?? null;
if (!$id) {
exit('記事IDが指定されていません');
}
/*
|--------------------------------------------------------------------------
| 記事取得
|--------------------------------------------------------------------------
*/
$stmt = $pdo->prepare("
SELECT *
FROM posts
WHERE id = :id
");
$stmt->bindValue(':id', $id, PDO::PARAM_INT);
$stmt->execute();
$post = $stmt->fetch();
if (!$post) {
exit('記事が見つかりません');
}
include '../header.php';
?>
<h2>記事編集</h2>
<form>
<p>
タイトル
</p>
<input
type="text"
name="title"
value="<?= htmlspecialchars($post['title'], ENT_QUOTES, 'UTF-8') ?>"
style="width:500px;"
>
<p>
本文
</p>
<textarea
name="content"
rows="10"
cols="80"
><?= htmlspecialchars($post['content'], ENT_QUOTES, 'UTF-8') ?></textarea>
<br><br>
<button type="submit">
更新する
</button>
</form>
<?php include '../footer.php'; ?>
$_GET['id'] ?? null
posts.php(記事一覧画面)から受け渡したidを取得しています。取得できない場合はエラーを避けるため未定義ではなく、nullを入れる形となっています。
if (!$id) {
exit('記事IDが指定されていません');
}
もしidがない(null)場合、注意文として「記事IDが指定されていません」を指定しています。
prepare()
SQLの準備。
SELECT *
FROM posts
WHERE id = :id
指定しているidが該当する記事情報を MySQL の postsテーブル からすべて呼び出しています。
bindValue(':id', $id, PDO::PARAM_INT)
bindValue()は、値の割り当て。今回では、「$id」の値を「:id」に割り当てしています。PDO::PARAM_INTは、「割り当ての値は整数型だよー」と伝えています。
execute()
SQLの実行。
fetch()
SQLの実行結果から1件だけデータを取得。
if (!$post) {
exit('記事が見つかりません');
}
もしpostがない(null)場合、注意文として「記事が見つかりません」を指定しています。
include '../header.php'; ~ include '../footer.php';
HTMLです。画面に必要なものを置きましょう。
動作確認(記事一覧画面→記事編集画面)
https://kimimachilab.com/portfolio/admin/posts.php
まず、posts.php(記事一覧画面)に「編集」ボタンが設置されているか確認。

「編集」ボタンの設置確認完了。次にedit-post.php(記事編集画面)へのリンクが作動しているか確認。

問題なく遷移していることを確認。
画面の崩れもなく、MySQL から記事情報も取得できていることを確認。
編集(Update)機能実装
edit-post.php(記事編集画面)ファイルへ記事更新処理を追加で記述
記事の更新機能を実装するため、さらに edit-post.php(記事編集画面)へ記述していきます。
$post = $stmt->fetch();
if (!$post) {
exit('記事が見つかりません');
}
(ここの部分へ)
include '../header.php';
更新処理を記述します。
$post = $stmt->fetch();
if (!$post) {
exit('記事が見つかりません');
}
/*
|--------------------------------------------------------------------------
| 更新処理
|--------------------------------------------------------------------------
*/
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$title = trim($_POST['title']);
$content = trim($_POST['content']);
$stmt = $pdo->prepare("
UPDATE posts
SET
title = :title,
content = :content
WHERE id = :id
");
$stmt->bindValue(':title', $title);
$stmt->bindValue(':content', $content);
$stmt->bindValue(':id', $id, PDO::PARAM_INT);
$stmt->execute();
header("Location: posts.php");
exit;
}
include '../header.php';
if ($_SERVER['REQUEST_METHOD'] === 'POST') {}
このページ(記事編集画面)が POST メソッドで送信されたときだけ処理を実行
$title = trim($_POST['title']); $content = trim($_POST['content']);
フォームから送信された「タイトル」と「本文」を取得。 前後の空白(スペース・改行・タブなど)を削除
prepare()
SQLの準備。
UPDATE posts
SET
title = :title,
content = :content
WHERE id = :id
postsテーブル 内で指定しているidが該当する「タイトル」と「本文」へ、フォームから送信された「タイトル」と「本文」を更新
$stmt->bindValue(':title', $title);
$stmt->bindValue(':content', $content);
$stmt->bindValue(':id', $id, PDO::PARAM_INT);
bindValue()は、値の割り当て。「$○○」の値を「:○○」に割り当て。PDO::PARAM_INTは、「割り当ての値は整数型だよー」と伝えています。
execute()
SQLの実行。
header("Location: posts.php");
ブラウザを posts.php(記事一覧画面)へ自動的に移動(リダイレクト)
exit;
PHPの処理を終了する宣言
動作確認(記事編集画面→編集→「更新」ボタンを押す→記事一覧画面へ戻される→記事一覧画面と記事編集画面で更新の反映を確認する)
https://kimimachilab.com/portfolio/admin/edit-post.php?id=(編集したい記事のid)

実際に編集を行い、「更新する」ボタンを押してみます。
タイトルを
「SNSシェア動作確認用テスト記事②」
↓
「SNSシェア動作確認用テスト記事②(編集済み)」
へ変更。

「更新する」ボタンを押す。
自動で posts.php(記事一覧画面)へ遷移し

posts.php(記事一覧画面)で、タイトルの編集が反映されていることを確認。
もう一度「編集」ボタンを押して

edit-post.php(記事編集画面)でも、タイトルの編集が反映されていることを確認。
削除(Delete)機能実装
posts.php(記事一覧画面)へ「削除」ボタンを設置
posts.php(記事一覧画面)へ「削除」ボタンを設置していきます。
<td>
<a href="edit-post.php?id=<?= $post['id'] ?>">
編集
</a>
</td>
<?php
require_once '../config/database.php';
$stmt = $pdo->query("
SELECT *
FROM posts
ORDER BY id DESC
");
$posts = $stmt->fetchAll();
?>
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>記事一覧</title>
</head>
<body>
<h1>記事一覧</h1>
<p>
<a href="new-post.php">新規投稿</a>
</p>
<table border="1" cellpadding="10">
<tr>
<th>ID</th>
<th>タイトル</th>
<th>投稿日</th>
</tr>
<?php foreach ($posts as $post): ?>
<tr>
<td><?= $post['id'] ?></td>
<td>
<?= htmlspecialchars($post['title'], ENT_QUOTES, 'UTF-8') ?>
</td>
<td><?= $post['created_at'] ?></td>
<td>
<a href="edit-post.php?id=<?= $post['id'] ?>">
編集
</a>
|
<a href="delete-post.php?id=<?= $post['id'] ?>">
削除
</a>
</td>
</tr>
<?php endforeach; ?>
</table>
</body>
</html>
href="delete-post.php"
削除ページへのリンクです。
id=<?= $post['id']
どの記事の削除画面か特定できないためidを受け渡し、delete-post.php 側で判別できるようにしています。
delete-post.php(記事削除画面)ファイルの作成
portfolio(個人開発環境)配下の admin(管理者画面)配下に delete-post.php(記事削除画面)ファイルの作成を行います。

portfolio/
│
├── index.php ← 記事一覧(フロント)
├── post.php ← 記事詳細(フロント)
├── header.php ← 共通ヘッダー
├── footer.php ← 共通フッター
├── style.css ← CSS
├── test-db.php ← DB接続テスト
├── test-posts.php ← 投稿取得テスト
│
├── config/
│ └── database.php ← PDO接続設定
│
└── admin/
└── index.php ← 管理トップ
├── posts.php ← 記事一覧(管理)
├── new-post.php ← 記事作成
├── edit-post.php ← 記事編集
└── delete-post.php ← 記事削除
delete-post.php(記事削除画面)ファイルへ記述
作成した delete-post.php(記事削除画面)へ記述していきます。
<?php
require_once '../config/database.php';
$id = $_GET['id'] ?? null;
if (!$id) {
exit('記事IDが指定されていません');
}
$stmt = $pdo->prepare("
SELECT *
FROM posts
WHERE id = :id
");
$stmt->bindValue(':id', $id, PDO::PARAM_INT);
$stmt->execute();
$post = $stmt->fetch();
if (!$post) {
exit('記事が見つかりません');
}
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$stmt = $pdo->prepare("
DELETE FROM posts
WHERE id = :id
");
$stmt->bindValue(':id', $id, PDO::PARAM_INT);
$stmt->execute();
header('Location: posts.php');
exit;
}
include '../header.php';
?>
<h2>記事削除</h2>
<p>
本当に削除しますか?
</p>
<h3>
<?= htmlspecialchars($post['title'], ENT_QUOTES, 'UTF-8') ?>
</h3>
<form method="POST">
<button type="submit">
削除する
</button>
</form>
<p>
<a href="posts.php">
キャンセル
</a>
</p>
<?php include '../footer.php'; ?>
$_GET['id'] ?? null
posts.php(記事一覧画面)から受け渡したidを取得しています。取得できない場合はエラーを避けるため未定義ではなく、nullを入れる形となっています。
if (!$id) {
exit('記事IDが指定されていません');
}
もしidがない(null)場合、注意文として「記事IDが指定されていません」を指定しています。
prepare()
SQLの準備。
SELECT *
FROM posts
WHERE id = :id
指定しているidが該当する記事情報を MySQL の postsテーブル からすべて呼び出しています。
bindValue(':id', $id, PDO::PARAM_INT)
bindValue()は、値の割り当て。今回では、「$id」の値を「:id」に割り当てしています。PDO::PARAM_INTは、「割り当ての値は整数型だよー」と伝えています。
execute()
SQLの実行。
fetch()
SQLの実行結果から1件だけデータを取得。
if (!$post) {
exit('記事が見つかりません');
}
もしpostがない(null)場合、注意文として「記事が見つかりません」を指定しています。
if ($_SERVER['REQUEST_METHOD'] === 'POST') {}
このページ(記事編集画面)が POST メソッドで送信されたときだけ処理を実行
DELETE FROM posts
WHERE id = :id
指定しているidが該当する記事情報を MySQL の postsテーブル からすべて削除しています。
header("Location: posts.php");
ブラウザを posts.php(記事一覧画面)へ自動的に移動(リダイレクト)
exit;
PHPの処理を終了する宣言
include '../header.php'; ~ include '../footer.php';
HTMLです。画面に必要なものを置きましょう。
動作確認(記事一覧画面→記事削除画面→「削除」ボタンを押す→「更新」ボタンを押す→記事一覧画面へ戻される→記事一覧画面で更新の反映を確認する)
https://kimimachilab.com/portfolio/admin/posts.php
まず、posts.php(記事一覧画面)に「削除」ボタンが設置されているか確認。

「削除」ボタンの設置確認完了。次にdelete-post.php(記事削除画面)へのリンクが作動しているか確認。

問題なく遷移していることを確認。
画面の崩れもなく、MySQL から記事情報も取得できていることを確認。
「削除する」ボタンを押す。
自動で posts.php(記事一覧画面)へ遷移し

posts.php(記事一覧画面)で、記事の削除が反映されていることを確認。
まとめ
今回は
「記事編集画面」「記事削除画面」の作成
「編集(Update)機能」「削除(Delete)機能」の実装
を行いました。
前回は、記事を作成・投稿までの最低限の機能を実装しましたが、
今回は、CRUD(クラッド)処理である
| Create | 作成 | 新しい記事を投稿する |
| Read | 読み取り | 記事を表示する |
| Update | 更新 | 記事を編集する |
| Delete | 削除 | 記事を削除する |
の実装を完了しました。
データを扱うシステムでの基本操作なので、一区切りといった印象です。
その他、WordPress自作開発についての記事を確認したい方は、こちらのカテゴリーを覗いていただければと思います。
カテゴリー「WordPress自作開発」
次回は、管理画面を操作できる権限の機能として「ログイン機能(Session)」の実装を予定しています。
ご興味があれば是非ご一読ください。
ここまで読んでいただき、ありがとうございました。
