WordPressの標準仕様ではセキュリティの懸念があるためアップロードできないようになっているSVGファイルをできるだけ安全にアップロードできるようにするコード、アップロードしたSVGファイルをフロント・バックエンドで表示させる方法を紹介します。
なお、安易に本ページのコードを使う前に、文末に書いている「SVGファイルを扱う必要性、SVGファイルのセキュリティ懸念について」をご覧いただき、自身のサイトで本当に必要なのかどうかを判断してから取り組むようにしてください。
本機能はSVG Repo – Free SVG Vectors and Iconsで無料提供されているSVGファイルを使用して動作確認したものですので、その他のSVGファイルではうまく動作しないかも知れません
SVGファイルをメディアにアップロードして使用する方法
本ページでは以下の順でSVGファイルをWordPressで扱えるようにします。
- SVGファイルのアップロードを許可する
- アップロードされたファイルに不正なコードがないかを検証し、不適切なファイルは削除する(サニタイズ)
- メディアのリスト表示での表示体裁を整える
- SVGファイルを表示させる(HTMLタグ、ショートコード)
特に2のサニタイズについては必ず必要ですので、もしも本ページのコードを使った場合に不具合が発生した場合には代替手段を探して必ずサニタイズを行うようにしてください(本ページのサニタイズ方法はかなりきつめにしていますから、これで通らない場合に簡易的なコードを使うことはセキュリティリスクが高まってしまう可能性がありますのでご注意ください)。
SVGファイルのアップロードを許可する
以下のコードを有効化しているテーマのfunctions.phpへ追加することで、ほとんどのサーバーではSVGファイルのアップロードが可能になります。
/*** SVG Mimeタイプのアップロードを許可 ***/
function pwcn_allow_svg_upload_mimes( $mimes ) {
$mimes['svg'] = 'image/svg+xml';
$mimes['svgz'] = 'image/svg+xml';
return $mimes;
}
add_filter( 'upload_mimes', 'pwcn_allow_svg_upload_mimes' );
このコードだけでは、不正なSVGファイルもアップロード可能になり、セキュリティリスクが高まってしまいますので、必ず次項のサニタイズを行う処理の追加をしてください
アップロードしたファイルを無害化(サニタイズ)する
アップロードしたファイルに対してセキュリティ上リスクとなる記述がないかを確認し、引っかかるものは削除する(保存を拒否して削除する)という処理を行います。
/*** アップロードされたSVGファイルをサニタイズ ***/
function pwcn_safe_svg_sanitize_after_upload( $file_info ) {
// エラーがある、または処理対象がSVGではない場合はスキップ
if ( isset( $file_info['error'] ) || $file_info['type'] !== 'image/svg+xml' ) {
return $file_info;
}
// 開発者設定で無制限アップロードが許可されている場合はスキップ(セキュリティ上の注意)
if ( defined( 'ALLOW_UNFILTERED_UPLOADS' ) && ALLOW_UNFILTERED_UPLOADS ) {
return $file_info;
}
$file_path = $file_info['file']; // メディアライブラリに保存されたファイルの絶対パス
// DOMDocumentのチェック
if ( ! class_exists( 'DOMDocument' ) ) {
// SVGファイルを削除し、エラーを返す
unlink( $file_path );
$file_info['error'] = __( 'エラー: DOMDocumentがインストールされていません. SVGファイルを削除しました.', '' );
return $file_info;
}
// 必要なコアファイルをロード(サニタイズにksesを使う)
if ( ! function_exists( 'wp_kses' ) ) {
require_once ABSPATH . WPINC . '/kses.php';
}
// 保存されたSVGファイルのコンテンツを取得
$svg_content = file_get_contents( $file_path );
if ( $svg_content === false ) {
// 読み込み失敗
unlink( $file_path );
$file_info['error'] = __( 'エラー: SVGファイルをアップロードできませんでした。ファイルを削除しました。', '' );
return $file_info;
}
// SVG要素と属性のホワイトリスト(前回と同じリストを使用)
$svg_allowed_tags = array(
'svg' => array( 'xmlns' => true, 'viewbox' => true, 'role' => true, 'aria-hidden' => true, 'width' => true, 'height' => true, 'preserveaspectratio' => true, 'version' => true ),
'g' => array( 'fill' => true, 'stroke' => true, 'transform' => true, 'opacity' => true ),
'path' => array( 'd' => true, 'fill' => true, 'stroke' => true, 'stroke-width' => true, 'fill-rule' => true ),
'circle' => array( 'cx' => true, 'cy' => true, 'r' => true, 'fill' => true, 'stroke' => true ),
'rect' => array( 'x' => true, 'y' => true, 'width' => true, 'height' => true, 'fill' => true, 'stroke' => true ),
'polygon' => array( 'points' => true, 'fill' => true, 'stroke' => true ),
'polyline' => array( 'points' => true, 'fill' => true, 'stroke' => true ),
'ellipse' => array( 'cx' => true, 'cy' => true, 'rx' => true, 'ry' => true, 'fill' => true, 'stroke' => true ),
'line' => array( 'x1' => true, 'y1' => true, 'x2' => true, 'y2' => true, 'stroke' => true, 'stroke-width' => true ),
'text' => array( 'x' => true, 'y' => true, 'font-size' => true, 'fill' => true, 'transform' => true ),
'defs' => array(), 'style' => array( 'type' => true ), 'title' => array(), 'desc' => array(), 'metadata' => array(),
);
// サニタイズを実行
$sanitized_svg = wp_kses( $svg_content, $svg_allowed_tags );
if ( $sanitized_svg ) {
// サニタイズ後のコンテンツで本ファイルを上書き(メディアライブラリへの書き込み権限は通常許可されている)
$result = file_put_contents( $file_path, $sanitized_svg );
if ( $result === false ) {
// 書き込み失敗(権限が厳しすぎる場合)
unlink( $file_path );
$file_info['error'] = __( 'エラー: 不正なSVGファイルである可能性があるため、ファイルを削除しました。', '' );
}
} else {
// サニタイズ後に空になった場合(危険な要素しかなかった場合)
unlink( $file_path ); // 危険なファイルを削除
$file_info['error'] = __( 'SVGファイルを正常にサニタイズできませんでした。ファイルを削除しました', '' );
}
return $file_info;
}
add_filter( 'wp_handle_upload', 'pwcn_safe_svg_sanitize_after_upload', 10, 2 );
ここまで終了した段階で、正常なSVGファイルを用意し、アップロードしてみてください。
アップロードできない場合のチェックポイント
まずは別のSVGファイルを用意してアップロードしてみてください。
本ページのサニタイズ処理段階で失敗している場合には、コードにもある通り、以下の理由が考えられます。
- SVG形式のファイルと認識されていない場合
- 不正と思われる記述がファイル内に含まれている
サニタイズコード内にあるエラーメッセージではなく、「ファイルをアップロードする権限がありません」とエラーメッセージが出る場合は、本コードの問題以前に、サーバーもしくはWordPress本体側で何等かのセキュリティが働いてアップロードできていないものと思われます。そうした場合にはwp-config.phpに許可の追記をすることで解決できるケースがありますが、無法地帯にしてしまうことになりますのでおすすめしません。
どうしてもエラーが出て解決できないときは、セキュリティの観点から素直にSVGファイルの扱いを止めた方がいいでしょう。
メディアのリスト表示での不具合を解消する
ここまでのコードを追加してアップロードできることは確認できましたが、メディアのリスト表示をしてみると、かなり小さく表示される(小さな点のように表示される)ことがあります。そのような場合には、以下のスタイルコードを管理画面側に適用できるスタイルシートへ追加することで改善できます。
img[src*='.svg'] {
width: 100%;
height: auto;
}
通常どこかで提供されている子テーマや親テーマには、管理画面側に対するスタイルを指定する機能が備わっていない場合がほとんどですので、もしも管理画面適用用のスタイルシートがない、または読み込まれていない場合にはテーマのfunctions.phpへ以下のコードを追加しても同じことができます(できれば管理画面用のスタイルシートを用意することをおすすめします)。
function pwcn_svg_media_list_style(){
?>
img[src*='.svg'] {
width: 100%;
height: auto;
}
<?php
}
add_action('admin_head','pwcn_svg_media_list_style');
以上でSVGファイルをWordPressサイトへアップロードできるようになりました。..で終わりではありませんね(笑)。
次項では肝心のアップロードしたSVGファイルを表示する方法を紹介していきます。
SVGファイルを表示させる
ショートコードで出力する
以下のコードを有効化しているテーマのfunctions.phpへ追加してください。
/*** ショートコードで出力 ***/
function pwcn_output_inline_svg_shortcode( $atts ) {
// 属性のデフォルト値を設定
$atts = shortcode_atts(
array(
'id' => 0, // 必須: メディアID
'class' => 'inline-svg', // デフォルトクラス名
'color' => '', // オプション: カスタム色(例: #FF0000, red, blue)
),
$atts,
'svg_inline'
);
$attachment_id = intval( $atts['id'] );
$css_class = esc_attr( $atts['class'] );
$custom_color = sanitize_hex_color( $atts['color'] ) ?: esc_attr( $atts['color'] ); // 色をサニタイズ
// --- エラーチェック
if ( $attachment_id <= 0 ) return current_user_can( 'edit_posts' ) ? '' : '';
$file_path = get_attached_file( $attachment_id );
if ( ! $file_path || ! file_exists( $file_path ) || get_post_mime_type( $attachment_id ) !== 'image/svg+xml' ) {
return current_user_can( 'edit_posts' ) ? "" : '';
}
$svg_content = file_get_contents( $file_path );
if ( ! $svg_content ) return current_user_can( 'edit_posts' ) ? "" : '';
$output = '';
// カスタム色が指定されている場合の処理
if ( ! empty( $custom_color ) ) {
// SVGタグのIDをクラス名に使用してCSSの詳細度を確保
$unique_class = 'svg-id-' . $attachment_id;
// ショートコードのクラスにユニークなIDクラスを追加
$css_class .= ' ' . $unique_class;
// SVG内の描画要素(path, circleなど)を対象にfillを指定するスタイル
$output .= '<style type="text/css">';
$output .= ".{$unique_class} path, .{$unique_class} circle, .{$unique_class} polygon, .{$unique_class} rect, .{$unique_class} g { fill: {$custom_color} !important; }";
$output .= '</style>';
}
// SVGタグにクラスを挿入
// str_ireplace: 大文字・小文字を区別せず最初の '<svg' を置換
$svg_content = str_ireplace(
'<svg',
'<svg class="' . trim( $css_class ) . '" style="width:100%;height:auto;"',
$svg_content,
$count
);
// 置換に成功した場合
if ( $count === 0 ) {
// <svg>タグが見つからない場合はそのまま出力 (非常に稀なケース)
$output .= $svg_content;
} else {
$output .= $svg_content;
}
return $output;
}
add_shortcode( 'pwcn-svg-inline', 'pwcn_output_inline_svg_shortcode' );
// wp-config.phpなどで定義されていない場合、sanitize_hex_color関数をロード
if ( ! function_exists( 'sanitize_hex_color' ) ) {
require_once ABSPATH . WPINC . '/class-wp-customize-manager.php';
}
追加したら、投稿編集画面を開き、以下のショートコードを挿入します。
[pwcn-svg-inline id="" class="" color=""]
idには画像のIDを、classには特別にCSSクラスを追加する際の文字列を、colorにはHEX値(白なら#ffffffなど)を指定し、プレビューして表示されていることを確認ください。
画像のIDはメディア一覧のリスト表示で「画像名」や「編集」をマウスオーバーした時画面下に表示されるURLの「id=〇〇」で確認できます
HTMLで表示する方法
カスタムHTMLブロックやテーマテンプレート内に以下のHTMLコードを記述します。
<img src="画像のURL" alt="SVGの代替テキスト" width="300" height="150" style="width:100%;height:auto;filter: invert(19%) sepia(99%) saturate(7400%) hue-rotate(357deg) brightness(100%) contrast(100%);">
HTMLコードで出力したSVG画像の色は基本色が黒なので、別の色にしたい場合には上記のようにfilterを使って指定します(上記は赤色にする場合のコードです)。
このfilter指定は一定法則に則っていないと色として表現できないので、「CSS Filter ジェネレーター」などを使っていちいち計算値を出して編集する必要がありちょっと面倒です。
従って個人的には前項のショートコードで出力する方法をおすすめします。
SVGファイルを扱う必要性、SVGファイルのセキュリティ懸念について
WordPressでSVGファイルをそのままアップロードしたり扱ったりすることができないようになっている最大の理由を簡単に説明すると、このファイルにはスクリプトなどを埋め込むことができ、セキュリティ対策なしでアップロードを可能にすることでサイト内外に悪意のあるコードを実行させることができる可能性があるからです。
本ページのコードでは、一旦メディアにアップロードしたSVGファイルに対してファイルの検証と無害化(サニタイズ)を行い、不正なコードが挿入されている場合には破棄するという形である程度のセキュリティを保ってはいるものの、完全とは言えませんし、他の参考サイトやページ等で紹介されているコードについても以下のような理由から確実に安全とは言えないと思います。
- 単純にSVGファイルをアップロード可能なファイル形式として登録するもの(セキュリティ対策なし)
- wp-configファイルにコードを追記してアップロード可能にするもの(セキュリティ対策なし)
- 簡易にサニタイズ処理を噛ませたもの(セキュリティリスク大)
そうした観点から、そもそもそのサイトでSVGファイルを扱う必要があるのか?というのを考えるのが妥当だと思います。
SVGファイルは簡単に言えば白いキャンバスの中に無数の点を指定していくことで形を作り出すファイルです。点のある部分に色を付ける(基本色は黒)ことで、白キャンバスの中に黒い点の集まりができ、画像や絵として表示されます。
このファイルの利点は他の画像形式と比べて圧倒的にファイルのサイズが小さいことで、アイコンを多用するようなサイトでは一見便利なように見えますが、そんな利用をするようなサイトはあまりないでしょうから、リスクのあるSVGファイルを扱うこと自体を考えたほうがいいでしょう(実際私も本ページのコードで扱えるようにはしたものの、出来上がった後であまり必要性がないことに気づき、現在これらのコードは使用せず、SVGファイルを扱うことをやめました)。
アイコンとして何かを追加したいということであれば、IcoMoon Appというサービスを使って、SVGファイルとCSSを結び付けて保存し、それをサイトへアップロードして使用するという方法の方が簡単かつセキュアな使い方ができると思います。
本サイトでは本サイトで配布している「Hima Art Utility」プラグインにおいて、IcoMoon Appを使用してアイコンフォントを表示させるようにしています。内容については以下の参考ページをご覧ください。








コメントを残す