WordPressでSVGをアップロードする方法|プラグインとコードの両方


WordPressは標準の状態ではSVGファイルをアップロードできません。使えるようにするには、サニタイズ機能を持つプラグインを入れるか、テーマやプラグイン側で許可するファイル形式にSVGを追加するかの二択です。どちらを選んでも、許可することとファイルを安全にすることは別の作業だという点は変わりません。

ロゴやアイコンをSVGで納品されたのに、メディアライブラリへドラッグしたら「セキュリティ上の理由から、このファイルタイプは許可されていません。」と弾かれた——という場面は、WordPressを触っていれば一度は通ります。検索すると「1行足せば使える」という記事と「SVGは危険だからやめろ」という記事が同時に出てきて、どちらを信じればいいのか判断できないのがこのテーマの厄介なところです。

この記事では、プラグインで許可する方法とコードで許可する方法の両方を手順つきで解説します。あわせて、コードを足したのにアップロードできないときに何が起きているのかをWordPressコアの実装まで踏み込んで説明し、許可したあとに必要になるサニタイズと権限の考え方までまとめました。


WordPressでSVGが使えない理由

WordPressはアップロードを許可するファイル形式をあらかじめ決めており、SVGはそこに入っていません。バグでも設定漏れでもなく、意図してそうなっています。

理由は、SVGが画像に見えて実体はテキストファイルであることにあります。JPEGやPNGが色の並びを記録したバイナリなのに対し、SVGはHTMLによく似たXMLで書かれた「図形の指示書」です。だからこそ拡大しても劣化せず、テキストエディタで中身を書き換えられるのですが、同じ性質のせいで次のようなものも書き込めてしまいます。

  • script要素に書いたJavaScript
  • onloadonclickのようなイベント属性
  • 外部のファイルを読みに行く参照や、別ページへの遷移を起こす記述

投稿できる人なら誰でもSVGを置ける状態は、誰でも任意のスクリプトを設置できる状態と紙一重です。WordPressが既定で許可していないのは、この距離の近さを避けるためです。逆に言えば、この距離さえきちんと詰めれば使ってよい形式であり、実際に多くのサイトが使っています。

なお、SVGファイルが単体で開かれたときと、img要素の中で画像として表示されたときでは危険度が違います。画像として読み込まれたSVGはブラウザ側でスクリプトが無効化されるためです。問題になるのは、アップロードされたファイルのURLを直接開いた場合や、テーマがSVGの中身をページに直接書き出している場合です。


3つの選択肢と選び方

取れる道は3つです。先に結論を書くと、迷ったらプラグインを選んでください。コードで許可する方法は行数こそ少ないものの、サニタイズが付いてこないぶん、あとから足すものが多くなります。

方法サニタイズ権限の制御向いている状況
プラグインを入れる付いてくるプラグイン側で設定できる複数人が投稿する/自分でコードを保守したくない
コードで許可する付いてこない(自分で用意する)自分で書く管理者ひとりで運用/プラグインを増やしたくない
PNGで代替する不要不要設定を変えられない/SVGでなければならない理由がない

3つ目を軽く見ないでください。SVGが必要なのは「拡大しても劣化させたくない」「ファイルを軽くしたい」「あとから色を変えたい」のいずれかに当てはまるときです。そのどれでもないなら、PNGで用が足ります。共有サーバーで複数人が投稿するサイトなら、無理に解禁しないという判断は十分に現実的です。


プラグインで許可する

定番は2つです。どちらも公式ディレクトリで有効インストール数100万以上、アップロード時のサニタイズと権限の制御を備えています。

Safe SVGSVG Support
開発元10upBenbodhi
バージョン2.4.02.6.1
設定項目ほぼ無し(入れれば効く)多め(権限・インライン化など)
特徴アップロード時に自動でサニタイズSVGをHTMLへ直接展開してCSSで操作できる
向いている人設定を増やさず安全側に倒したいSVGの色をCSSで変えたい

Safe SVGはWordPress関連の開発会社10upが公開しており、サニタイズにはsvg-sanitizerという専用ライブラリを使っています(出典: WordPress.org プラグインディレクトリ Safe SVG)。設定画面をほとんど持たないのが特徴で、有効化した時点で「許可」と「無害化」の両方が済みます。

SVG Supportは設定項目が多く、役割ごとのアクセス制御に加えて、SVGをHTMLに直接展開する「インライン化」に対応しています(出典: WordPress.org プラグインディレクトリ SVG Support)。インライン化すると外側のCSSがSVGの中身に届くようになるため、1枚のファイルを配色違いで使い回せます

導入の手順

  1. 管理画面の「プラグイン」→「新規プラグインを追加」で、プラグイン名を検索する
  2. インストールして有効化する
  3. アップロードを許す権限の設定があれば、必要な範囲まで絞る
  4. メディアライブラリにSVGをドラッグして、通ることを確認する

プラグインを2つとも入れる必要はありません。同じ役割のものを重ねると、どちらの設定が効いているのか分からなくなります。どちらか片方だけにしてください。


コードで許可する

アップロードを許可するファイル形式はupload_mimesフィルターで足せます。WordPress 2.0から用意されている標準の仕組みです。

add_filter( 'upload_mimes', function ( $mimes ) {
    $mimes['svg'] = 'image/svg+xml';
    return $mimes;
} );

これだけで、拡張子.svgのファイルが許可リストに入ります。ただしこの3行は全員に許可を出す書き方です。投稿者や寄稿者がいるサイトでは、権限で絞ってください。

add_filter( 'upload_mimes', function ( $mimes ) {
    // 管理者以外には許可を出さない
    if ( ! current_user_can( 'manage_options' ) ) {
        return $mimes;
    }

    $mimes['svg'] = 'image/svg+xml';
    return $mimes;
} );

どこに書くか

置き場所は2つあります。子テーマのfunctions.phpか、サイト固有の小さなプラグインを作ってそこに書くかです。テーマを乗り換える可能性があるならプラグイン側が安全です。テーマに書いた場合、テーマを変えた瞬間にSVGがアップロードできなくなり、原因を思い出すまでに時間を取られます。

親テーマのfunctions.phpを直接編集するのは避けてください。テーマの更新で上書きされて消えます。functions.phpに処理を足していく進め方に慣れていない場合は、WordPressカスタマイズ入門|functions.php便利コード集で全体像を掴んでおくと迷いません。


追加したのにアップロードできないとき

upload_mimesに足したのに、まだ「許可されていません」と言われる——このテーマで最も混乱する場面です。原因は、WordPressが許可リストを見る前に、もう一段の検査をしていることにあります。

WordPressコアのwp_check_filetype_and_ext()は、ファイル名の拡張子から決まるMIMEタイプと、サーバーが中身を読んで判定した実際のMIMEタイプを突き合わせます。そして画像系の形式については、この2つが完全に一致しない場合は危険とみなして拒否します(WordPress 7.0系のコアコードで確認)。拡張子を.svgに変えただけの別形式のファイルを弾くための仕組みです。

ここで問題になるのが、中身からMIMEタイプを判定する処理がサーバーの環境に依存することです。PHPのfileinfo拡張が使う判定データベースの版によって、同じSVGでもimage/svg+xmlと返る環境と、image/svgtext/xmlと返る環境があります。後者だと突き合わせに失敗し、許可リストに入れていても弾かれます。

自分の環境がどう判定するか調べる

推測で対策を足す前に、実際の判定結果を見てください。PHPが動く環境なら次の2行で分かります。

$finfo = finfo_open( FILEINFO_MIME_TYPE );
echo finfo_file( $finfo, '/path/to/icon.svg' );

SSHが使えるなら、コマンド1本でも確認できます。

file --mime-type icon.svg

ここでimage/svg+xmlと返るなら、突き合わせは通ります。つまり「upload_mimesに足すだけでは絶対に通らない」というのは正確ではありません。手元の環境(PHP 8.4系)で試したところ、XML宣言の有無にかかわらずimage/svg+xmlと判定され、追加の対策なしで通りました。まず調べる、というのが遠回りに見えて一番早い手順です。

判定が食い違う環境での対処

調べた結果がimage/svg+xml以外だった場合は、突き合わせの結果を上書きするwp_check_filetype_and_extフィルターで対処します。拡張子がSVGのときだけに限定するのが最低条件です。

add_filter( 'wp_check_filetype_and_ext', function ( $data, $file, $filename, $mimes ) {
    // 拡張子が .svg のときだけ、コアの判定結果を上書きする
    if ( 'svg' !== strtolower( pathinfo( $filename, PATHINFO_EXTENSION ) ) ) {
        return $data;
    }

    $data['ext']  = 'svg';
    $data['type'] = 'image/svg+xml';

    return $data;
}, 10, 4 );

ただしこれはコアの安全装置を一部外す操作です。この状態は「拡張子が.svgなら中身を問わずSVGとして受け入れる」ことを意味するため、次に説明するサニタイズと必ずセットにしてください。ここまで来ると、素直にプラグインへ寄せたほうが結果的に安全で手間も少なくなります。


許可とサニタイズは別の作業

ここがこのテーマの本丸です。upload_mimesで許可を出しても、アップロードされるファイルの中身は一切検査されません。素通しになるだけです。「1行足せば使える」という説明が危ういのは、この一点が抜けているからです。

サニタイズとは、SVGの中から危険になり得る記述を取り除く処理のことです。プラグインが内部で使っているsvg-sanitizerのようなライブラリは、おおむね次のようなものを削ります。

  • 許可リストにない要素(scriptなど)
  • onで始まるイベント属性
  • スクリプトを実行し得るリンクや外部参照

コードで許可する道を選ぶ場合は、この処理を自分で用意する必要があります。具体的には、サニタイズ用のライブラリをComposerで導入し、アップロードを横取りするフックでファイルの中身を通してから保存する——という作りになります。これはプラグインが内部でやっていることと同じで、自作するとその分の保守も自分で背負います。

用意しないなら、SVGをアップロードできるのは自分だけという状態を維持するのが最低条件です。自分で作った素材と、信頼できる配布元から入手した素材しか置かない、という運用ルールとセットで考えてください。

受け取ったSVGが不安なときは、アップロード前にテキストエディタで開いてみるのが確実です。SVGはテキストなので中身がそのまま読めます。scriptという文字列やonで始まる属性が見当たらなければ、まず問題ありません。図形の座標と色の指定しか書かれていないファイルは、見ればすぐ分かります。


誰にアップロードを許すか

SVGの解禁は、技術の問題であると同時に運用の問題です。同じサイトでも、誰が投稿するかで危険度がまったく変わります

サイトの形推奨理由
自分ひとりで運用どちらでもよい置くファイルを自分で把握できる
社内の数人で運用プラグイン+権限を管理者に限定素材の出所が人によって変わる
外部ライターが寄稿プラグイン必須/原則は許可しない受け取ったファイルの中身を毎回は確認できない
会員が画像を投稿できる解禁しない不特定多数がファイルを持ち込める

クライアントのサイトに実装する場合は、納品後に運用する人が増えても壊れない設計を選んでください。自分ひとりの想定でコードを書いて許可を出したまま引き渡すと、あとから増えた投稿者にも同じ権限が渡ります。プラグイン側で権限を絞れる構成にしておけば、管理画面から見直せます。


アップロードできたあとのつまずき

メディアライブラリで真っ白に見える

一覧のサムネイルが空白になったり、ファイル名だけが並んだりします。WordPressがSVGから縦横の寸法を取得できないためで、壊れているわけではありません。プラグインによっては表示を補正してくれます。

記事に入れると巨大になる・逆に潰れる

同じ理由で、投稿に挿入したときのサイズが安定しないことがあります。ブロックの幅設定で指定するか、widthheightを明示してください。SVGは拡大しても劣化しないので、表示側でサイズを決めて構いません。

CSSで色を変えられない

画像として貼ったSVGには、ページ側のCSSが届きません。色を変えたいなら、SVGを直接HTMLに展開する(インライン化する)か、色違いのファイルを用意します。この制限と回避策は動くアイコンを無料でダウンロードできるツールの記事で仕組みから説明しています。

ファイルが思ったより重い

デザインツールから書き出したSVGには、編集用のメタ情報や使われていない定義が残っていることがあります。中身がテキストなので、開けば何が入っているか見えます。不要な記述を削るか、画像圧縮ツールのようにSVGに対応した圧縮を通してから使ってください。


SVGを使わずに済ませる判断

ここまで手順を書いておいてなんですが、解禁しないという選択も立派な答えです。判断は次の3点で足ります。

使いたい理由SVGが要るか代わりの手
大きく表示しても劣化させたくない要る表示サイズの2倍で書き出したPNGでも実用上は足りる
ファイルを軽くしたい要る場合が多いアイコン程度ならPNGでも数KBに収まる
あとからCSSで色を変えたい要る(インライン化が前提)色違いのPNGを用意する
アイコンを動かしたい要る代替なし(PNGは動かない)

ロゴやアイコンを大きく見せるページ、印刷にも回す素材、動かしたいアイコンならSVGの価値があります。記事中の小さな挿絵や装飾なら、PNGで十分です。1枚のためにサイト全体の許可設定を変える必要はありません


よくある質問

Q. プラグインとコード、結局どちらがいいですか?

迷うならプラグインです。コードで許可する方法はサニタイズが付いてこないため、安全に運用するには結局それに相当する処理を自分で用意することになります。プラグインを増やしたくないという理由だけで選ぶには、負う手間が見合いません。

Q. コードを書いたのにアップロードできません。

まず、サーバーがそのファイルをどのMIMEタイプと判定しているかを調べてください。image/svg+xml以外が返る環境では、許可リストに入れていてもコアの検査で弾かれます。判定結果を見てから対策を決めるのが最短です。

Q. SVGを許可するとサイトが危険になりますか?

許可しただけでは危険にも安全にもなりません。危険度を決めるのは「誰がアップロードできるか」と「中身を検査しているか」の2つです。管理者だけが自分の作った素材を置くなら、実質的なリスクはほとんどありません。

Q. すでにアップロード済みのSVGはどうなりますか?

あとからサニタイズ機能のあるプラグインを入れても、既存のファイルが自動的に洗われるとは限りません。プラグイン導入前に置いたSVGがある場合は、中身を確認するか、いったん削除して入れ直すのが確実です。

Q. テーマを変えたらSVGが使えなくなりました。

許可の処理をテーマのfunctions.phpに書いていた場合、テーマを切り替えると処理ごと外れます。テーマに依存させたくないなら、サイト固有のプラグインとして切り出すか、プラグインでの許可に切り替えてください。

Q. SVGはSEOに有利ですか?

形式そのものに有利不利はありません。関係するとすれば、ファイルが軽くなって表示速度が改善する場合です。逆に、装飾用のSVGに不要なaltを書き込むと読み上げの邪魔になるため、意味を持たない画像はaltを空にしてください。

Q. 動くSVGもアップロードできますか?

できます。アニメーションをCSSで持つSVGは、動きの指示をファイル内に含んだ普通のSVGなので、許可さえ通れば画像として貼るだけで動きます。JavaScriptを使わないぶん、サニタイズで動きが失われる心配もありません。


まとめ

WordPressでSVGを使えるようにする道は、サニタイズ付きのプラグインを入れるか、upload_mimesで許可を出すかの二択です。前者は入れた時点で「許可」と「無害化」が揃い、後者は許可だけが手に入ります。この差が、そのまま選択の基準になります。

そして、うまくいかないときは推測で対策を重ねないことです。サーバーがそのファイルをどう判定しているかを1行で調べてから動く。この順番を守るだけで、原因の分からない試行錯誤はほとんど消えます。設定が終わったら、置く素材の出所と、アップロードできる人の範囲を決めておいてください。技術より運用が効くのが、この話の結論です。

使うSVG素材そのものを探している場合は、動きの付いたアイコンをそのままダウンロードできるツールを公開しています。商用利用可・クレジット表記不要で、静止SVGと透過PNGも同じ画面から書き出せます。

WordPressのカスタマイズ全般はWordPress実践ガイドに、テーマ開発で使う関数はWordPress関数一覧にまとめてあります。

関連記事