【WordPress】SVGを投稿記事のサムネイルに!自作プラグイン(未実装🤷♂️)「nonce(ナンス)トークン」wp_postmetaテーブルを利用
更新日:2025/02/14

試した内容:
- メタデータへのSVGコードの保存(成功)
- フックの優先度調整(1-99で試行)
- 初期化タイミングの調整(plugins_loaded, init, after_setup_theme)
- サムネイル表示フィルターの複数追加(post_thumbnail_html, get_post_thumbnail_html)
- デバッグログの追加と分析
考えられる問題点:
- テーマのサムネイル表示処理が標準的でない可能性
- 独自のサムネイル表示関数を使用している可能性
- フィルターをバイパスしている可能性
- フックのタイミング問題
- サムネイル表示時に既にフィルターが実行済みの可能性
- テーマの読み込みタイミングとの不整合
- テンプレート側の制約
- CSSの競合
- テンプレートが特定の画像形式を想定している
推奨される次のステップ:
- テーマの functions.php でサムネイル表示がどのように処理されているか確認
- テーマ側でサムネイルを表示している箇所のコードを確認
- get_the_post_thumbnail() の代わりに独自関数を使用することを検討
提案される検証方法:
- デフォルトテーマ(Twenty Twenty-Four など)での動作確認
- テーマの サムネイル表示部分に直接デバッグコードを追加
- フィルターが実際に呼び出されているか確認するためのテスト関数の追加
処理内容
プラグイン読み込み ~ クラス初期化の流れ
メタボックスの追加 ~ 投稿画面での入力
メタボックスは記事編集画面でSVGコード入力用のエリアのUIのことです
nonce は “Number used once“(一度だけ使われる数値)という意味で、フォーム送信時のCSRF対策や改ざん防止のために使われる トークン(合言葉) です
「nonceを生成し、**隠しフィールド(input type=”hidden”)**として出力」
⬇️
第三者が不正なURLで投稿を勝手に更新したり、ボタン押下の偽装を行うといった攻撃を防ぐ
投稿保存時の処理
メタボックスで送信されたSVGコードは、記事のカラム(wp_posts内)に直接追加されるのではなく、wp_postmetaテーブルに「メタデータ」として格納される。
wp_postmeta テーブルとは
1つの投稿に対して複数の追加情報を柔軟に保存できる仕組みです
投稿IDをキーとして紐づけています。
+-----------+---------+----------------------+---------------+
| meta_id | post_id | meta_key | meta_value |
+-----------+---------+----------------------+---------------+
| (自動ID) | 123 | _svg_code_thumbnail | <svg>...</svg>|
+-----------+---------+----------------------+---------------+
デバッグすべきポイント
サムネイル置換とフロント表示
<?php
/*
Plugin Name: SVG Code Thumbnail Fixed
Description: SVGコードを直接サムネイルとして使用(修正版10)
Version: 2.6
Author: Ida
*/
if (!defined('ABSPATH')) exit;
class SVG_Code_Thumbnail {
private static $instance = null;
private $nonce_action = 'svg_code_nonce_action';
private $nonce_name = 'svg_code_nonce_field';
private $meta_key = '_svg_code_thumbnail';
private $debug = true;
private $current_user;
private $initialized = false;
public static function get_instance() {
if (null === self::$instance) {
self::$instance = new self();
}
return self::$instance;
}
private function __construct() {
$this->log_debug('プラグインインスタンス作成開始');
if (!function_exists('wp_get_current_user')) {
require_once(ABSPATH . 'wp-includes/pluggable.php');
}
$user = wp_get_current_user();
$this->current_user = $user->ID ? $user->user_login : 'unknown';
$this->log_debug('ユーザー情報取得', [
'user' => $this->current_user,
'time' => current_time('mysql')
]);
// initフックで初期化
add_action('init', [$this, 'initialize'], 0);
}
public function initialize() {
if ($this->initialized) {
return;
}
$this->initialized = true;
$this->log_debug('プラグイン初期化開始');
// メタボックス関連
add_action('add_meta_boxes', [$this, 'add_meta_box']);
add_action('save_post', [$this, 'save_svg'], 10, 2);
// サムネイル関連
add_filter('post_thumbnail_html', [$this, 'replace_thumbnail'], 10, 5);
add_filter('has_post_thumbnail', [$this, 'check_thumbnail'], 10, 2);
add_filter('wp_kses_allowed_html', [$this, 'allow_svg'], 10, 2);
// スタイル
if (is_admin()) {
add_action('admin_head', [$this, 'admin_styles']);
} else {
add_action('wp_head', [$this, 'front_styles']);
}
$this->log_debug('プラグイン初期化完了');
}
private function log_debug($message, $data = null) {
if ($this->debug) {
$timestamp = current_time('mysql');
$user = $this->current_user ?? 'unknown';
error_log("[{$timestamp}] [{$user}] SVG_DEBUG: {$message}");
if ($data !== null) {
error_log("[{$timestamp}] [{$user}] SVG_DEBUG_DATA: " . print_r($data, true));
}
}
}
public function add_meta_box() {
$this->log_debug('メタボックス追加開始');
$post_types = ['post', 'page', 'recipe'];
foreach ($post_types as $post_type) {
add_meta_box(
'svg_code_thumbnail',
'SVGサムネイル',
[$this, 'render_meta_box'],
$post_type,
'side',
'high'
);
}
$this->log_debug('メタボックス追加完了');
}
public function render_meta_box($post) {
$this->log_debug('メタボックスレンダリング開始', ['post_id' => $post->ID]);
wp_nonce_field($this->nonce_action, $this->nonce_name);
$svg_code = get_post_meta($post->ID, $this->meta_key, true);
?>
<div class="svg-code-editor">
<p>
<label for="svg_code_input">SVGコードを入力:</label>
<textarea id="svg_code_input"
name="svg_code_input"
class="large-text code"
rows="8"
placeholder="ここにSVGコードを入力してください"><?php echo esc_textarea($svg_code); ?></textarea>
</p>
<?php if (!empty($svg_code)) : ?>
<div class="svg-preview">
<p>プレビュー:</p>
<?php echo wp_kses($svg_code, $this->allow_svg([], 'post')); ?>
</div>
<p class="description">
最終更新: <?php echo get_the_modified_time('Y-m-d H:i:s', $post->ID); ?><br>
更新者: <?php echo get_the_modified_author(); ?>
</p>
<?php endif; ?>
</div>
<?php
$this->log_debug('メタボックスレンダリング完了', ['post_id' => $post->ID]);
}
public function save_svg($post_id, $post) {
try {
$this->log_debug('保存処理開始', [
'post_id' => $post_id,
'post_type' => $post->post_type,
'user' => $this->current_user
]);
if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) {
$this->log_debug('自動保存をスキップ');
return;
}
if (!isset($_POST[$this->nonce_name])) {
$this->log_debug('Nonceが見つかりません');
return;
}
if (!wp_verify_nonce($_POST[$this->nonce_name], $this->nonce_action)) {
$this->log_debug('Nonce検証失敗');
return;
}
if (!current_user_can('edit_post', $post_id)) {
$this->log_debug('権限不足');
return;
}
if (isset($_POST['svg_code_input'])) {
$svg_code = wp_unslash($_POST['svg_code_input']);
$this->log_debug('SVGコード受信', ['length' => strlen($svg_code)]);
if (!empty($svg_code)) {
$sanitized_svg = wp_kses($svg_code, $this->allow_svg([], 'post'));
$result = update_post_meta($post_id, $this->meta_key, $sanitized_svg);
$this->log_debug('SVG保存結果', [
'success' => $result ? 'true' : 'false',
'meta_key' => $this->meta_key
]);
} else {
delete_post_meta($post_id, $this->meta_key);
$this->log_debug('空のSVGコード - メタ削除');
}
}
} catch (Exception $e) {
$this->log_debug('エラー発生', [
'message' => $e->getMessage(),
'trace' => $e->getTraceAsString()
]);
}
}
public function replace_thumbnail($html, $post_id, $thumbnail_id, $size, $attr) {
$svg_code = get_post_meta($post_id, $this->meta_key, true);
if (!empty($svg_code)) {
$this->log_debug('SVGサムネイル置換', [
'post_id' => $post_id,
'size' => $size
]);
$width = 150;
$height = 150;
if (is_array($size)) {
$width = $size[0];
$height = $size[1];
}
return sprintf(
'<div class="svg-thumbnail" style="width: %dpx; height: %dpx;">%s</div>',
esc_attr($width),
esc_attr($height),
wp_kses($svg_code, $this->allow_svg([], 'post'))
);
}
return $html;
}
public function check_thumbnail($has_thumbnail, $post_id) {
$has_svg = !empty(get_post_meta($post_id, $this->meta_key, true));
$this->log_debug('サムネイルチェック', [
'post_id' => $post_id,
'has_thumbnail' => $has_thumbnail,
'has_svg' => $has_svg
]);
return $has_thumbnail || $has_svg;
}
public function allow_svg($tags, $context) {
return array_merge($tags, [
'svg' => [
'xmlns' => true,
'viewbox' => true,
'width' => true,
'height' => true,
'class' => true,
'style' => true,
'fill' => true,
'preserveAspectRatio' => true
],
'path' => [
'd' => true,
'fill' => true,
'style' => true,
'stroke' => true,
'stroke-width' => true
],
'circle' => [
'cx' => true,
'cy' => true,
'r' => true,
'fill' => true,
'style' => true
],
'rect' => [
'x' => true,
'y' => true,
'width' => true,
'height' => true,
'fill' => true,
'style' => true
],
'g' => [
'fill' => true,
'transform' => true,
'style' => true
]
]);
}
public function front_styles() {
?>
<style>
.svg-thumbnail {
display: block;
overflow: hidden;
background: #f8f9fa;
margin: 0 auto;
}
.svg-thumbnail svg {
width: 100%;
height: 100%;
display: block;
object-fit: contain;
}
</style>
<?php
}
public function admin_styles() {
?>
<style>
.svg-code-editor {
margin: 1em 0;
}
.svg-code-editor textarea {
resize: vertical;
font-family: monospace;
margin-bottom: 1em;
}
.svg-preview {
background: #f8f9fa;
padding: 15px;
margin: 1em 0;
border: 1px solid #ddd;
border-radius: 4px;
}
.svg-preview svg {
max-width: 100%;
height: auto;
display: block;
margin: 0 auto;
}
.description {
color: #666;
font-style: italic;
margin-top: 0.5em;
}
</style>
<?php
}
}
// プラグインの初期化
function init_svg_thumbnail() {
return SVG_Code_Thumbnail::get_instance();
}
add_action('plugins_loaded', 'init_svg_thumbnail', 0);
- 主な機能:
- 投稿編集画面にSVGサムネイル入力用のメタボックスを追加
- SVGコードの安全な保存と表示
- プレビュー機能
- 既存のサムネイル表示システムとの統合
- 使用方法:
- プラグインを有効化
- 投稿編集画面でSVGコードを入力
- 通常のサムネイル表示箇所にSVGが表示される
- セキュリティ対策:
- SVGコードのサニタイズ
- 許可する要素と属性の制限
- 適切なユーザー権限チェック

-
検索
(例) debug search etc.. -
カテゴリー
-
Windows↔️Macで文字化けしたZIPファイルを解決する方法【7-Zip活用ガイド】
更新日:2025/02/18
-
本番環境 / ステージング環境 でのGitブランチ切り替え方法と注意点 Note: witching to ‘origin/new_feature’. You are in ‘detached HEAD’ state…
更新日:2025/02/16
-
複数のWordPressサイトをまとめて検索・管理するには?
更新日:2025/02/16
-
【WordPress】SVGを投稿記事のサムネイルに!自作プラグイン(未実装🤷♂️)「nonce(ナンス)トークン」wp_postmetaテーブルを利用
更新日:2025/02/14
-
【WordPress】カスタムフィールド作成の仕方「ACF」Advanced Custom Fieldsの使用法
更新日:2024/06/10
298 view
-
mixhostでのWordPress利用について
更新日:2024/04/02
295 view
-
scrollHint
更新日:2024/03/13
246 view
-
LOLIPOPでWordPressインストール(サブディレクトリにインストールしたWordPressをドメイン直下で表示)
更新日:2024/06/13
235 view
-
XML Sitemap Generator for Google不具合のダウングレード対応、代替プラグイン
更新日:2024/06/13
234 view
-
Sass導入方法
更新日:2024/03/13
206 view
-
【SnowMonkey】納品までのフローまとめ
更新日:2025/02/15
163 view
-
【Snow Monkey】Googleサーチコンソール登録
更新日:2024/05/28
157 view
-
ワードプレスでフォントを変えたいとき、プラグインを使えば初心者でも簡単
更新日:2025/02/16
144 view
-
【Googleサーチコンソール】検索画面で表示させたくない「Googleのインデックス削除」
更新日:2024/06/07
129 view
-
【ショートコード】編集画面で任意の場所にHTMLファイルを挿入
更新日:2024/01/26
122 view
-
tailwindcss使い方
更新日:2024/03/13
119 view
-
キーワード検索で上位表示させる方法【SEO】
更新日:2023/10/28
119 view
-
Recline: GitHub Copilotで動作するClaude 3.5 Sonnet搭載の開発支援ツール
更新日:2025/01/20
105 view
-
WordPressプラグイン「All-in-One WP Migration」のトラブル
更新日:2022/03/31
83 view
-
【2022年】WordPressセキュリティー対策おすすめプラグイン2選
更新日:2022/02/21
70 view
-
【必須】ワードプレスセキュリティー対策まとめ【2022年】
更新日:2025/02/16
69 view
-
「THE THOR」を半年使ってみて、レビュー【メリット・デメリット】
更新日:2025/02/16
45 view
-
SSHを使用してGitHubのリポジトリをクローン、複数の接続元で公開鍵をディレクトリで区別する方法
更新日:2025/01/13
43 view
-
VSCodeで開発効率を劇的に向上させる!Roo-Clineプラグイン完全ガイド【Gemini API】
更新日:2025/02/08
41 view
-
「JSONスキーマ」と「Few-shot Learning」で実現する次世代生成AIソフトウェア開発の可能性
更新日:2025/02/12
40 view
-
THE THOR(ザ・トール)でグーグルアドセンスを使う
更新日:2025/02/16
39 view
-
WordPressの無料画像素材のおすすめダウンロードサイト!
更新日:2022/02/22
35 view
-
リファクタリング【VSCode Javasctipt Python】
更新日:2025/02/06
34 view
-
形態素解析とは?初心者でもわかるツールの使い方と実践例
更新日:2025/02/08
33 view
-
【Next.js AWS】音声文字起こし&要約、分析アプリケーション(S3)(Transcribe)(Amazon Bedrock)
更新日:2025/02/13
28 view
-
VSCodeプラグイン「 Pretter – Code formatter」「PHP Intelephense 」
更新日:2025/01/06
26 view
-
【CSS JavaScript サンプルコード】アコーディオン 続きを読む(Read more)Toggle 折りたたみコンテンツ
更新日:2025/02/05
23 view
-
【WordPress】SVGを投稿記事のサムネイルに!自作プラグイン(未実装🤷♂️)「nonce(ナンス)トークン」wp_postmetaテーブルを利用
更新日:2025/02/16
22 view
-
【WordPressプラグイン】人気記事 管理 WordPress Popular Posts 実践的なカスタマイズ
更新日:2025/02/15
22 view
-
Googleアドセンスとは?〜前編〜
更新日:2025/02/16
22 view
-
【WordPress】プラグイン不使用でカスタムタクソノミーを設定、絞り込み検索について
更新日:2025/01/26
18 view
-
スマートフォンファーストのWeb開発実践ガイド
更新日:2025/01/23
16 view
-
WordPressでカスタムフィールドを使った記事のスコアリングシステムの実装
更新日:2025/01/27
15 view
-
AWSのOCRサービス完全ガイド:Textract、Rekognition、Comprehendの使い分け
更新日:2025/02/09
14 view