Written by Anonymous
// 管理メニューへの登録
add_action('admin_menu', function () {
add_menu_page(
'吹き出し',
'吹き出し',
'manage_options',
'cocoon-balloon-list-simple',
'render_balloon_list_with_filter',
'dashicons-format-chat',
25
);
});
add_action('wp_ajax_balloon_preview_iframe', function() {
if (!isset($_GET['id'])) wp_die();
global $wpdb;
$record = $wpdb->get_row($wpdb->prepare(
"SELECT * FROM " . SPEECH_BALLOONS_TABLE_NAME . " WHERE id = %d",
intval($_GET['id'])
));
if (!$record) wp_die();
$theme_css = get_template_directory_uri() . '/style.css';
$style = esc_attr($record->style);
$position = ($record->position === 'r') ? 'sbp-r' : 'sbp-l';
$think = ($record->style === 'think') ? 'sb-think' : '';
$iconstyle= esc_attr($record->iconstyle);
?>
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="<?php echo esc_url($theme_css); ?>">
<style>
html, body {
margin: 0;
padding: 0;
background: transparent;
width: 100%;
height: 100%;
overflow: hidden;
}
body {
display: flex;
align-items: center;
justify-content: flex-start;
}
.preview-root {
transform-origin: left center;
}
.speech-wrap { margin: 0 !important; }
.speech-balloon p { margin: 0 !important; }
</style>
</head>
<body>
<div class="preview-root" id="previewRoot">
<div class="speech-wrap <?php echo $position; ?> sbs-<?php echo $style; ?> sbis-<?php echo $iconstyle; ?> clearfix">
<div class="speech-person">
<div class="speech-icon">
<img src="<?php echo esc_url($record->icon); ?>" class="speech-icon-image">
</div>
<?php if ($record->name): ?>
<div class="speech-name"><?php echo esc_html($record->name); ?></div>
<?php endif; ?>
</div>
<div class="speech-balloon <?php echo $think; ?>">
<div class="speech-balloon-content">
<p>ここに入力したテキストが表示されます。</p>
</div>
</div>
</div>
</div>
<script>
window.addEventListener('load', () => {
const root = document.getElementById('previewRoot');
const iframeWidth = document.documentElement.clientWidth;
const iframeHeight = document.documentElement.clientHeight;
const rect = root.getBoundingClientRect();
const scale = Math.min(
iframeWidth / rect.width,
iframeHeight / rect.height,
1
);
root.style.transform = `scale(${scale})`;
});
</script>
</body>
</html>
<?php
exit;
});
/**
* メインの一覧画面をレンダリング
*/
function render_balloon_list_with_filter() {
global $wpdb;
$table_name = SPEECH_BALLOONS_TABLE_NAME;
$base_page_url = admin_url('admin.php?page=speech-balloon');
// フォームからの検索キーワードとソート順を取得
$search = isset($_POST['s']) ? sanitize_text_field($_POST['s']) : '';
$order_val = isset($_POST['order']) ? $_POST['order'] : 'date DESC, id DESC';
// 基本となるSQLクエリの構築
$query = "SELECT * FROM $table_name";
// 検索条件がある場合はWHERE句を追加
if (!empty($search)) {
$query .= $wpdb->prepare(" WHERE title LIKE %s", '%' . $wpdb->esc_like($search) . '%');
}
// 許可されたソート条件かチェックし、ORDER BY句を付与
$allowed_orders = ['title', 'title DESC', 'date', 'date DESC, id DESC', 'modified', 'modified DESC, id DESC'];
$order_sql = in_array($order_val, $allowed_orders) ? $order_val : 'date DESC, id DESC';
$query .= " ORDER BY $order_sql";
// 最終的なレコード取得
$records = $wpdb->get_results($query);
?>
<div class="wrap">
<h1 class="wp-heading-inline">吹き出し</h1>
<a href="<?php echo add_query_arg('action', 'new', $base_page_url); ?>" class="page-title-action">新規追加</a>
<hr class="wp-header-end">
<form method="post" action="">
<div class="tablenav top">
<div class="alignleft actions">
<select name="order">
<option value="title" <?php selected($order_val, 'title'); ?>>タイトル昇順</option>
<option value="title DESC" <?php selected($order_val, 'title DESC'); ?>>タイトル降順</option>
<option value="date" <?php selected($order_val, 'date'); ?>>作成日昇順</option>
<option value="date DESC, id DESC" <?php selected($order_val, 'date DESC, id DESC'); ?>>作成日降順</option>
<option value="modified" <?php selected($order_val, 'modified'); ?>>編集日昇順</option>
<option value="modified DESC, id DESC" <?php selected($order_val, 'modified DESC, id DESC'); ?>>編集日降順</option>
</select>
<input type="submit" class="button action" value="抽出">
</div>
<div class="search-box" style="margin-bottom: 5px;">
<input type="search" name="s" value="<?php echo esc_attr($search); ?>" placeholder="タイトル検索">
<input type="submit" class="button" value="検索">
</div>
<br class="clear">
</div>
</form>
<table class="wp-list-table widefat fixed striped posts">
<thead>
<tr>
<th scope="col" class="manage-column column-title column-primary" style="width: 30%;">タイトル</th>
<th scope="col" class="manage-column column-preview">プレビュー</th>
</tr>
</thead>
<tbody id="the-list">
<?php if ($records): foreach ($records as $record):
// 各種リンクとiframeソースの準備
$edit_url = add_query_arg(['action' => 'edit', 'id' => $record->id], $base_page_url);
$delete_url = add_query_arg(['action' => 'delete', 'id' => $record->id], $base_page_url);
$iframe_src = admin_url('admin-ajax.php?action=balloon_preview_iframe&id=' . $record->id);
?>
<tr class="iedit author-self level-0 status-publish">
<td class="title column-title has-row-actions column-primary">
<strong><a class="row-title" href="<?php echo $edit_url; ?>"><?php echo esc_html($record->title); ?></a></strong>
<div class="row-actions">
<span class="edit"><a href="<?php echo $edit_url; ?>">編集</a> | </span>
<span class="trash"><a href="<?php echo $delete_url; ?>" class="submitdelete" onclick="return confirm('本当に削除しますか?');">削除</a></span>
</div>
</td>
<td class="column-preview">
<iframe src="<?php echo esc_url($iframe_src); ?>" style="width:100%; height:80px; border:none; pointer-events:none; display:block;"></iframe>
</td>
</tr>
<?php endforeach; else: ?>
<tr class="no-items"><td colspan="2">データが見つかりませんでした。</td></tr>
<?php endif; ?>
</tbody>
</table>
</div>
<style>
.wp-list-table td {
vertical-align: middle!important;
}
.row-actions {
visibility: hidden;
margin-top: 4px;
}
tr:hover .row-actions {
visibility: visible;
}
.tablenav .actions {
padding: 0;
}
.search-box {
float: right;
}
</style>
<?php
}