WordPress 預設編輯器 TinyMCE 基於 HTML5 規範驗證標籤,SVG 作為 XML 命名空間元素,預設會被視為無效標籤而於視覺/文字模式切換時被剝離。本文提供經實測可行的完整解決方案,讓內聯 SVG 在編輯器中保持完整結構、樣式與互動性。
valid_elements、extended_valid_elements 預設不包含 SVG 標籤。valid_children 規則限制 <body> 等容器不允許 SVG 子元素。viewBox、clipPath),但 HTML 解析器會強制小寫,導致屬性失效。<?php
/**
* 讓 TinyMCE 完整支援內聯 SVG
* 掛載至 tiny_mce_before_init 過濾器
*/
add_filter('tiny_mce_before_init', function (array $init): array {
// 1. 完整 SVG 元素白名單 (全部小寫,符合 HTML 解析器行為)
$svgElements = 'svg[*]';
$svgChildElements = implode(',', [
'altGlyph[*]', 'altGlyphDef[*]', 'altGlyphItem[*]', 'animate[*]', 'animateColor[*]',
'animateMotion[*]', 'animateTransform[*]', 'circle[*]', 'clipPath[*]', 'color-profile[*]',
'cursor[*]', 'defs[*]', 'desc[*]', 'ellipse[*]', 'feBlend[*]', 'feColorMatrix[*]',
'feComponentTransfer[*]', 'feComposite[*]', 'feConvolveMatrix[*]', 'feDiffuseLighting[*]',
'feDisplacementMap[*]', 'feDistantLight[*]', 'feFlood[*]', 'feFuncA[*]', 'feFuncB[*]',
'feFuncG[*]', 'feFuncR[*]', 'feGaussianBlur[*]', 'feImage[*]', 'feMerge[*]', 'feMergeNode[*]',
'feMorphology[*]', 'feOffset[*]', 'fePointLight[*]', 'feSpecularLighting[*]', 'feSpotLight[*]',
'feTile[*]', 'feTurbulence[*]', 'filter[*]', 'font[*]', 'font-face[*]', 'font-face-format[*]',
'font-face-name[*]', 'font-face-src[*]', 'font-face-uri[*]', 'foreignObject[*]', 'g[*]',
'glyph[*]', 'glyphRef[*]', 'hkern[*]', 'image[*]', 'line[*]', 'linearGradient[*]', 'marker[*]',
'mask[*]', 'metadata[*]', 'missing-glyph[*]', 'mpath[*]', 'path[*]', 'pattern[*]', 'polygon[*]',
'polyline[*]', 'radialGradient[*]', 'rect[*]', 'script[*]', 'set[*]', 'stop[*]', 'style[*]',
'switch[*]', 'symbol[*]', 'text[*]', 'textPath[*]', 'title[*]', 'tref[*]', 'tspan[*]', 'use[*]',
'view[*]', 'vkern[*]'
]);
// 2. 擴充合法元素
$init['extended_valid_elements'] = isset($init['extended_valid_elements'])
? $init['extended_valid_elements'] . ',' . $svgElements . ',' . $svgChildElements
: $svgElements . ',' . $svgChildElements;
// 3. 允許 body 等容器包含 svg 子元素
$init['valid_children'] = isset($init['valid_children'])
? $init['valid_children'] . ',+body[svg],+div[svg],+figure[svg],+section[svg],+article[svg]'
: '+body[svg],+div[svg],+figure[svg],+section[svg],+article[svg]';
// 4. 自訂元素註冊 (支援自訂屬性)
$init['custom_elements'] = isset($init['custom_elements'])
? $init['custom_elements'] . ',' . $svgElements
: $svgElements;
// 5. 保留屬性大小寫 (關鍵:防止 viewBox 變 viewbox)
// TinyMCE 4.x+ 支持此設定
$init['verify_html'] = false; // 關閉 HTML 驗證,避免移除未知屬性
$init['cleanup'] = false; // 關閉自動清理
$init['forced_root_block'] = false; // 不強制包裹 p 標籤
return $init;
}, 20); // 優先權較高,確保後執行
<svg viewBox="0 0 100 100" xmlns="https://www.w3.org/2000/svg">
<title>圖示標題</title>
<desc>圖示描述,供螢幕閱讀器讀取</desc>
<circle cx="50" cy="50" r="40" fill="currentColor"/>
<!-- 瀏覽器不支援 SVG 時的備用內容 -->
<text x="50" y="55" text-anchor="middle" font-size="10" fill="gray">SVG 不支援</text>
</svg>
<svg class="my-icon" ...>...</svg>
.my-icon { width: 1em; height: 1em; display: inline-block; vertical-align: middle; }
.my-icon * { vector-effect: non-scaling-stroke; }
WordPress 5.8+ 區塊編輯器已大幅改善 SVG 支援。若使用區塊編輯器:
@wordpress/create-block),提供屬性面板(顏色、尺寸、圖示選擇),輸出安全的內聯 SVG。allowedBlockTypes、wp_kses_allowed_html 可進一步微調。script[*], style[*], foreignObject[*] 等元素可能引入 XSS 風險,**僅限可信任編輯者使用**。wp_kses 白名單過濾儲存前的內容,或使用 DOMPurify (PHP 移植版) 淨化。| 現象 | 原因 | 解決 |
|---|---|---|
| SVG 仍被移除 | 快取、CDN、其他外掛衝突 | 清除瀏覽器/伺服器快取,停用其他 TinyMCE 相關外掛測試 |
| 屬性變小寫 (viewBox → viewbox) | HTML 解析器特性 | SVG 規範屬性實際不區分大小寫,瀏覽器渲染無影響。若需保持,需關閉 verify_html |
| 樣式失效 | 主題 CSS 覆蓋、缺少 xmlns | 補上 xmlns="https://www.w3.org/2000/svg",加入 scoped CSS |
| 無法儲存 | wp_kses 過濾 | 使用 wp_kses_allowed_html 過濾器擴充允許標籤/屬性 |
透過 tiny_mce_before_init 完整註冊 SVG 元素樹、關閉 HTML 驗證、配合編輯習慣與安全過濾,即可在 WordPress 經典編輯器中流暢使用內聯 SVG。新專案建議直接採用區塊編輯器開發專用 SVG 區塊,獲得更佳的編輯體驗與輸出安全性。