サイトでデータを貯めておきたい場合(例:不特定多数の人が編集可能な表を作ったり)、バックエンドのどこかに更新内容を保存できるデータベースが必要です。データベースがなければ、サイトに入力した内容は、サイトを閉じると消えてしまいます。
幸いにも、WordPressでは、サイトをホストしているFTP(サイトのデータが登録されているフォルダーのようなもの)にカスタムテーブルを作成することができます。
実際にデータベースを活用して作ったものはこちら。画像もテーブルに直接保存してます。
手順
- 自分のWordPressサイトをホストしているサービスにログインします。
自分の場合は「ロリポップ!」というサービスです。 - ログインしたら、FTPにアクセスします。
wp-content/plugins
のディレクトリに、新しいディレクトリcustom-table
を作成します。wp-content/plugins/custom-table
のディレクトリに、custom-table.php
というファイルを作成し、中身にテーブルを作成する下記を入力して保存する。文字コードはUTF-8にしておいた方がいいです。
<?php
/*
Plugin Name: My Custom Table Creator
Description: A simple plugin to create a custom database table.
Version: 1.0
Author: guregu321
*/
function create_custom_table() {
global $wpdb;
// The name of our custom table
$table_name = $wpdb->prefix . 'custom_table_spatoon3_special';
// The database charset and collate should be used.
$charset_collate = $wpdb->get_charset_collate();
// SQL statement to create the table
$sql = "CREATE TABLE $table_name (
id mediumint(9) NOT NULL AUTO_INCREMENT,
special tinytext NOT NULL,
name tinytext NOT NULL,
score mediumint NOT NULL,
PRIMARY KEY (id)
) $charset_collate;";
require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
dbDelta($sql);
}
// Hook the function to the plugin activation hook
register_activation_hook(__FILE__, 'create_custom_table');
?>
- WordPressのダッシュボードにログインし、「インストール済みプラグイン」を開く。
- PHPで作成した「My Custom Table Creator」があるので有効化するとテーブルが作成される。(プラグインを無効化してもテーブルは削除されないので注意。削除する場合は、削除するPHPを実行しなければいけない。)
- 作成したテーブルは、phpMyAdminから確認ができます。自分は「ロリポップ!」からアクセスできました。なんならphpMyAdminから直接テーブル作成してもいいです。
- テーブルを開いたら、テスト用に「挿入」からレコードを追加しておく。
- 上のPHPファイルの中身をテーブルのデータを取得するコードに置き換えます。あとは、サイトのショートコードブロックまたはカスタムHTMLブロックに
スペシャル 名前 回数 アメフラシ やまち 7 ウルトラショット ぐれ 12 ウルトラハンコ ぐれ 12 エナジースタンド ぐれ 12 カニタンク ぐれ 11 キューインキ ぐれ 10 グレートバリア ぐれ 11 サメライド ぐれ 9 ジェットパック ぐれ 12 ショクワンダー Keisuke 10 テイオウイカ Keisuke,ぐれ 10 デコイチラシ Keisuke 12 トリプルトルネード Keisuke,ぐれ 13 ナイスダマ Keisuke 13 ホップソナー Keisuke 12 マルチミサイル ぐれ 11 メガホンレーザー5.1ch ぐれ 14
function populate_custom_table() {
global $wpdb;
// Fetch data from custom table
$table_name = $wpdb->prefix . 'custom_table_spatoon3_special';
$results = $wpdb->get_results( "SELECT * FROM $table_name" );
$style = ' .modern-table {
border-collapse: collapse;
background-color: #fff;
color: #333;
box-shadow: 0 2px 15px rgba(0, 0, 0, 0.1);
}
.modern-table td,
.modern-table th {
padding: 0px 10px 0px 10px;
text-align: left;
border: none;
}
.modern-table td[contenteditable="true"] {
background-color: #E8F4FF;
border: 1px dashed #5AC8FA;
}
.modern-table tr:first-child th,
.modern-table tr:first-child td {
font-weight: bold;
}
.modern-table tr {
background-color: #f6f6f6;
}
.modern-table input[type=text],
.modern-table select {
width: 100%;
border: 1px solid #ccc;
padding: 5px;
font-size: 14px;
border-radius: 5px;
box-sizing: border-box;
transition: border-color 0.3s ease;
}
.modern-table input[type=text]:focus,
.modern-table select:focus {
border-color: #5AC8FA;
outline: none;
}';
// Start the table HTML
$table_html = '<style>' . $style . '</style>';
$table_html .= '<table class="modern-table">
<tbody>
<tr>
<th>スペシャル</th>
<th>名前</th>
<th>回数</th>
</tr>';
// Loop through each result and add to table
$row_id = 1;
foreach( $results as $row ) {
$table_html .= '<tr>
<td>' . esc_html( $row->special ) . '</td>
<td contenteditable="true" data-id="' . $row_id . '" data-column="name">' . esc_html( $row->name ) . '</td>
<td contenteditable="true" data-id="' . $row_id . '" data-column="score">' . esc_html( $row->score ) . '</td>
</tr>';
$row_id++;
}
// Close the table HTML
$table_html .= '</tbody></table>';
return $table_html;
}
add_shortcode( 'custom_table', 'populate_custom_table' );
- 次は、データの変更をデータベースに反映するための設定をします。PHPと同じディレクトリにedit-table.jsを作成し、中身に下記を入力して保存する。
document.addEventListener('DOMContentLoaded', function () {
const editableCells = document.querySelectorAll('td[contenteditable="true"]');
editableCells.forEach(function (cell) {
cell.addEventListener('blur', function () {
let password = prompt("パスワードを入力してね!");
if (password === null) return;
let id = cell.getAttribute('data-id');
let column = cell.getAttribute('data-column');
let value = cell.innerText;
jQuery.post(ajax_object.ajax_url, {
action: 'save_table_data',
nonce: ajax_object.nonce,
password: password,
id: id,
column: column,
value: value
}, function (response) {
alert(response);
});
});
});
});
- そしてPHPに下記のコードを追加します。これでサイト上でデータを更新したときに、データベースにも反映されるようになります。
function enqueue_custom_scripts() {
wp_enqueue_script('edit-table-script', plugin_dir_url(__FILE__) . '/edit-table.js', array('jquery'), '1.0', true);
wp_localize_script('edit-table-script', 'ajax_object', array('ajax_url' => admin_url('admin-ajax.php'), 'nonce' => wp_create_nonce('edit_table_nonce')));
}
add_action('wp_enqueue_scripts', 'enqueue_custom_scripts');
function save_table_data() {
global $wpdb;
// Check the nonce for security
$nonce = $_POST['nonce'];
if (!wp_verify_nonce($nonce, 'edit_table_nonce')) {
die('Permission denied.');
}
// Password check
$input_password = sanitize_text_field($_POST['password']);
$correct_password = "パスワード"; // Set your desired password here
if ($input_password !== $correct_password) {
echo "パスワードが違います!";
wp_die();
}
$id = intval($_POST['id']);
$column = sanitize_text_field($_POST['column']);
$value = sanitize_text_field($_POST['value']);
$table_name = $wpdb->prefix . 'custom_table_spatoon3_special';
$result = $wpdb->update($table_name, array($column => $value), array('id' => $id));
if ($result === false) {
echo "Error: " . $wpdb->last_error;
wp_die();
}
echo "データが更新されました!";
wp_die();
}
add_action('wp_ajax_save_table_data', 'save_table_data'); // For logged-in users
add_action('wp_ajax_nopriv_save_table_data', 'save_table_data'); // For non-logged-in users
※スマホだと、ブラウザかWordPressのキャッシュ機能で最新のデータを毎回取得してくれませんでした。なので、Ajax経由でコードが毎回実行されるようにしました。まずはPHPに以下を追加する。
function load_custom_table_data() {
echo populate_custom_table();
wp_die();
}
add_action('wp_ajax_load_custom_table_data', 'load_custom_table_data'); // For logged-in users
add_action('wp_ajax_nopriv_load_custom_table_data', 'load_custom_table_data'); // For non-logged-in users
そして、JavaScriptを以下に書き換える。
document.addEventListener('DOMContentLoaded', function () {
// Load table data
loadTableData();
function loadTableData() {
// Show a loading message or spinner here (optional)
document.querySelector('#tableContainer').innerHTML = "Loading...";
jQuery.post(ajax_object.ajax_url, {
action: 'load_custom_table_data',
nonce: ajax_object.nonce,
}, function (response) {
// Replace the content of a container (e.g., div) with the table data
document.querySelector('#tableContainer').innerHTML = response;
attachEditableEvents(); // Once the table is loaded, attach the editable events to the cells
});
}
function attachEditableEvents() {
const editableCells = document.querySelectorAll('td[contenteditable="true"]');
editableCells.forEach(function (cell) {
cell.addEventListener('blur', function () {
let password = prompt("パスワードを入力してね!");
if (password === null) return;
let id = cell.getAttribute('data-id');
let column = cell.getAttribute('data-column');
let value = cell.innerText;
jQuery.post(ajax_object.ajax_url, {
action: 'save_table_data',
nonce: ajax_object.nonce,
password: password,
id: id,
column: column,
value: value
}, function (response) {
alert(response);
});
});
});
}
});
※画像を処理するPHPは以下にしました。
// ##################################
// ############# Load Image #############
// ##################################
function fetch_image_data()
{
global $wpdb;
$id = intval($_POST['id']);
$table_name = $wpdb->prefix . 'custom_table_spatoon3_special';
$row = $wpdb->get_row($wpdb->prepare("SELECT image_mime_type, image_data FROM $table_name WHERE id = %d", $id));
if ($row) {
wp_send_json_success([
'mime_type' => $row->image_mime_type,
'image_data' => base64_encode($row->image_data),
]);
} else {
wp_send_json_error([
'message' => 'Image not found.',
]);
}
}
add_action('wp_ajax_fetch_image_data', 'fetch_image_data'); // For logged-in users
add_action('wp_ajax_nopriv_fetch_image_data', 'fetch_image_data'); // For non-logged-in users
// ##################################
// ############# Upload Image #############
// ##################################
function upload_image_data()
{
global $wpdb;
// Check the nonce for security
$nonce = $_POST['nonce'];
if (!wp_verify_nonce($nonce, 'edit_table_nonce')) {
die('Permission denied.');
}
// Password check
$input_password = sanitize_text_field($_POST['password']);
$correct_password = "パスワード"; // Set your desired password here
if ($input_password !== $correct_password) {
echo "グルの名前が違います!";
wp_die();
}
$id = $_POST['id'];
$file = $_FILES['image_data'];
// Get the image data and mime type
$image_data = file_get_contents($file['tmp_name']);
$image_mime_type = $file['type'];
$table_name = $wpdb->prefix . 'custom_table_spatoon3_special';
$result = $wpdb->update($table_name, array('image_data' => $image_data, 'image_mime_type' => $image_mime_type), array('id' => $id));
if ($result === false) {
echo "Error: " . $wpdb->last_error;
wp_die();
}
echo "データが更新されました!";
wp_die();
}
add_action('wp_ajax_upload_custom_table_image', 'upload_image_data');
add_action('wp_ajax_nopriv_upload_custom_table_image', 'upload_image_data');
画像を処理するJavaScriptは以下の通り。
jQuery(document).on('click', '.image-link', function (e) {
e.preventDefault();
const imageId = jQuery(this).data('id');
jQuery.post(ajax_object.ajax_url, {
action: 'fetch_image_data',
nonce: ajax_object.nonce,
id: imageId
}, function (response) {
if (response.success && response.data) {
openImageInNewTab(event, response.data.mime_type, response.data.image_data);
} else {
alert(response.data);
}
});
function openImageInNewTab(event, mimeType, base64Data) {
event.preventDefault();
// Convert base64 data to blob
const byteCharacters = atob(base64Data);
const byteNumbers = new Array(byteCharacters.length);
for (let i = 0; i < byteCharacters.length; i++) {
byteNumbers[i] = byteCharacters.charCodeAt(i);
}
const byteArray = new Uint8Array(byteNumbers);
const blob = new Blob([byteArray], { type: mimeType });
// Create object URL and open in new tab
const objectUrl = URL.createObjectURL(blob);
window.open(objectUrl);
}
});
jQuery(document).ready(function () {
// Handle the upload button click
jQuery(document).on('click', '.upload-image-btn', function () {
var rowId = jQuery(this).data('id');
console.log("Initial Row ID:", rowId);
var targetInput = jQuery('.image-upload-input[data-id="' + rowId + '"]');
console.log(targetInput.length); // This should log '1' if the input is found.
targetInput.click();
});
// Handle the actual image selection
jQuery(document).on('change', '.image-upload-input', function (event) {
event.stopPropagation();
var rowId = jQuery(this).data('id');
console.log("Second Row ID:", rowId);
var file = this.files[0];
if (file) {
let password = prompt("グルの名前を入力してね!");
if (password === null) return;
let special = jQuery(this).attr('data-special');
let isConfirmed = window.confirm(special + "の画像を更新しますか?");
if (!isConfirmed) {
return;
}
var formData = new FormData();
formData.append('image_data', file);
formData.append('nonce', ajax_object.nonce);
formData.append('action', 'upload_custom_table_image');
formData.append('password', password);
formData.append('id', rowId);
jQuery.ajax({
url: ajax_object.ajax_url,
type: 'POST',
data: formData,
contentType: false,
processData: false,
success: function (response) {
if (response === "グルの名前が違います!") {
jQuery('.image-upload-input[data-id="' + rowId + '"]').val(''); // Reset the file input
}
alert(response);
}
});
} else {
console.log("File was not properly selected");
}
});
});