嵌入非 WordPress 檔案的方法

整理在 WordPress 文章中嵌入非 WordPress 檔案的兩種做法:shortcode 直接 include,或 iframe 搭配 postMessage 自動調整高度。以 coverage_calculator 計算器示範如何隔離 Blocksy 佈景主題 CSS,避免全域樣式衝突。

嵌入非 WordPress 檔案有兩種實用做法,可讓你在 WordPress 文章中自然顯示獨立的 HTML/CSS/JS 工具,同時避免 Blocksy 等佈景主題的全域樣式干擾。本文以站內的 產品用量計算器(coverage_calculator)為實例,說明 shortcode 直接輸出與 iframe 隔離樣式兩種嵌入非 WordPress 檔案的方法,並附上可複製的程式碼與檢查清單。

方法 1:以 shortcode 嵌入非 WordPress 檔案

此短代碼會接收檔名與資料夾路徑,組合成絕對路徑並檢查檔案是否存在,接著透過輸出緩衝(output buffering)輸出檔案內容。此方法速度快,且資源仍留在自家伺服器上;但可能因 WordPress 的全域 CSS 與背景樣式差異而顯得突兀。詳細實作可參考 WordPress Shortcode API 官方文件。

方法 2:以 iframe 嵌入非 WordPress 檔案

父頁面監聽同源(same-origin)的 postMessage 高度事件,並(可選)設定最小高度以調整 iframe;而 iframe 內的頁面會在載入、視窗尺寸變更與 DOM 變動時回報自身的捲動高度。跨頁溝通可參考 MDN:Window.postMessage()

需要 伺服器端直接插入內容 時選方法 1(shortcode);需要 更強的樣式隔離 時選方法 2(iframe)。無論採用哪種方式,都應為檔案做版本控管,並在行動裝置上測試效能與無障礙體驗。

什麼是「非 WordPress 檔案」?

「非 WordPress 檔案」指的是不透過佈景主題或外掛載入、而是以獨立 HTML 頁面運作的資源,例如放在網站根目錄的 /coverage-calculator/index_hk.htmlstyles.csscoverage.json。這類工具通常有自己的版面與互動邏輯,適合產品計算器、顏色對照表等情境。

若你想在 WordPress 文章或頁面中展示這些工具,就需要學會嵌入非 WordPress 檔案,而不是把整份 HTML 直接貼進 Gutenberg 編輯器。站內另一個類似案例是 跨標準顏色對照 工具,同樣以獨立檔案形式維護,再嵌入到 WordPress 內容中。

為什麼不直接放進佈景主題?

Blocksy 等現代佈景主題會為 bodyh1p 等全域選擇器設定樣式。若你把非 WordPress 頁面的 CSS 直接混入文章,這些規則可能連帶影響頁首、頁尾與選單,造成版面錯亂。

因此,嵌入非 WordPress 檔案時應優先考慮樣式隔離:要嘛用 iframe 建立獨立文件環境,要嘛把選擇器限制在 .coverage-calculator 這類容器前綴內。這也是本文推薦兩種方法的原因。

嵌入非 WordPress 檔案 — shortcode 與 iframe 嵌入示意

兩種方法怎麼選?

比較項目方法 1:shortcode方法 2:iframe
樣式隔離較弱,可能受主題 CSS 影響強,iframe 內為獨立文件
實作難度低,在 functions.php 註冊即可中,需父子頁面 postMessage 腳本
載入速度較快,無額外文件框架略慢,但可 lazy-load
維護方式檔案放於 ABSPATH 指定路徑同上,另需維護高度回報腳本
適用情境簡單靜態片段、樣式已限縮互動工具、計算器、複雜 UI

若你的工具像 coverage_calculator 一樣有表單互動與動態高度,建議優先採用 iframe;若只是嵌入一小段已限縮 CSS 的 HTML,shortcode 會更省事。

部署與除錯建議

完成程式碼整合後,建議先在 staging 環境驗證嵌入非 WordPress 檔案的每個環節。首先檢查檔案是否能以瀏覽器直接開啟,例如 /coverage-calculator/index_hk.html;若獨立頁面正常,再測試嵌入後的 WordPress 文章或頁面。這個順序能快速判斷問題來自檔案本身,還是來自主題或外掛的樣式覆寫。

若 shortcode 回傳「File not found」,通常是 ABSPATHpath 參數組合錯誤,或檔案未部署到 production 伺服器。請在 shortcode 函式中暫時記錄 $file_path,並以 SSH 或主機檔案總管確認實體路徑。相對路徑必須以網站根目錄為基準,而不是佈景主題資料夾。

iframe 方案常見的另一個問題是高度停留在固定值,導致內容被裁切或出現大片空白。請開啟瀏覽器開發者工具,在 Console 觀察子頁面是否送出 postMessage,並確認父頁面收到的 event.origin 與目前網域一致。若網站啟用快取外掛,記得排除含 iframe 腳本的頁面,避免舊版 JavaScript 被快取。

最後,建議為這類技術文章建立固定維護流程:當計算器或對照工具更新時,同步檢查嵌入頁面、重新快取,並補充變更紀錄。這能在數月後仍能理解當初為何選擇 shortcode 或 iframe,以及如何安全地嵌入非 WordPress 檔案

實作前檢查清單

  • 確認檔案路徑以 ABSPATH 為基準,並在部署後驗證 file_exists() 回傳 true。
  • 為 HTML、CSS、JS 建立版本控管(Git 或標記版本號),避免快取舊檔案。
  • 在行動裝置與桌面版分別測試嵌入結果,確認 iframe 高度自動調整正常。
  • 檢查鍵盤操作與螢幕閱讀器是否能正常使用嵌入的工具。
  • 確認 postMessage 僅接受同源訊息,避免第三方腳本竄改 iframe 高度。

方法 1:以 shortcode 嵌入非 WordPress 檔案

嵌入非 WordPress 檔案:shortcode 嵌入概念示意圖

編輯路徑:/www/<專案名稱>/public_html/wp-content/themes/<佈景主題名稱>/functions.php

例如

function embed_coverage_calculator_shortcode($atts) {
    $atts = shortcode_atts(array(
        'file' => 'index.html',  // e.g., 'myfile.html'
        'path' => '/coverage-calculator/'  // Your folder path
    ), $atts);
    
    $file_path = ABSPATH . $atts['path'] . $atts['file'];
    
    if (file_exists($file_path)) {
        ob_start();
        include $file_path;
        return ob_get_clean();
    }
    return 'File not found.';
}
add_shortcode('embed_coverage_calculator', 'embed_coverage_calculator_shortcode');
Code language: JavaScript (javascript)

在文章中加入短代碼 。

[embed_coverage_calculator]Code language: JSON / JSON with Comments (json)

優點:最快且最簡單。

缺點:若 WordPress 背景與嵌入文章的背景不同,差異可能會顯現。

方法 2:以 iframe 嵌入非 WordPress 檔案

嵌入非 WordPress 檔案的 styles.css 可能包含 bodyh1p 等全域選擇器。若在一般 Blocksy 頁面直接載入該檔案,可能會連帶重新樣式化頁首、頁尾及選單。

嵌入非 WordPress 檔案:iframe 嵌入概念示意圖
  • 使用 iframe:將計算器頁面置於 Blocksy 頁面的 iframe 中(主題樣式不會相互干擾)。
  • 限制 CSS 作用範圍:將計算器包裹在容器中,例如 <div class="coverage-calculator">,並將 CSS 選擇器改為以 .coverage-calculator 開頭(雖然工作量較大,但能完美整合)。

將以下內容加入 WordPress 頁面(父頁面)的自訂 HTML 區塊中,並設定 iframe 會自動調整大小以符合其內容高度

<iframe
  id="coverageCalcFrame"
  src="/coverage-calculator/index_en.html"
  style="width:100%; border:0; display:block;"
  loading="lazy"
></iframe>

<script>
(function () {
  const iframe = document.getElementById('coverageCalcFrame');
  if (!iframe) return;

  function onMessage(event) {
    // security: only accept same-origin messages
    if (event.origin !== window.location.origin) return;
    if (!event.data || event.data.type !== 'coverageCalc:height') return;

    const h = Number(event.data.height);
    if (!Number.isFinite(h) || h <= 0) return;

    // optional: minimum height
    iframe.style.height = Math.max(h, 600) + 'px';
  }

  window.addEventListener('message', onMessage, false);
})();
</script>
Code language: HTML, XML (xml)

將此內容加入 index.html(位於 iframe 頁面內,即非 WordPress 頁面),並將 HTML 包裹在 <div> 標籤中

<script>
(function () {
  function sendHeight() {
    const height = Math.max(
      document.body ? document.body.scrollHeight : 0,
      document.documentElement ? document.documentElement.scrollHeight : 0
    );

    // only works if parent exists and is same tab
    window.parent && window.parent.postMessage(
      { type: 'coverageCalc:height', height },
      window.location.origin
    );
  }

  // initial + after layout settles
  window.addEventListener('load', function () {
    sendHeight();
    setTimeout(sendHeight, 150);
    setTimeout(sendHeight, 500);
  });

  // update when content changes / viewport changes
  window.addEventListener('resize', sendHeight);

  // auto-detect DOM changes
  const mo = new MutationObserver(function () {
    sendHeight();
  });

  mo.observe(document.documentElement, { childList: true, subtree: true, attributes: true });
})();
</script>
Code language: HTML, XML (xml)

在 index.html 頁面內容中將內容包裹成類似以下格式:

<div class="coverage-calculator">
  <div id="root"></div>
</div>
Code language: HTML, XML (xml)

如果非 WordPress 頁面的 CSS 與主題(例如 Blocksy)的 CSS 不同,修改 styles.css,使每個選擇器前綴為 .coverage-calculator,並移除 body 的樣式設定:

  • body { ... } 改為 .coverage-calculator { ... }
  • * { ... } 改為 .coverage-calculator, .coverage-calculator * { ... }
  • h1 { ... } 改為 .coverage-calculator h1 { ... }…以此類推。

常見問題(FAQ)

Q:shortcode 嵌入後,工具背景與文章背景不一致怎麼辦?
A:這是方法 1 的常見現象。可改為 iframe,或把工具 CSS 的背景色改為與文章一致,並用容器 class 限縮選擇器範圍。

Q:iframe 高度沒有自動更新?
A:請確認子頁面有送出 coverageCalc:height 訊息、父頁面有監聽 message 事件,且兩者為同源網域。DOM 變動後可透過 MutationObserver 再次回報高度。

Q:可以把 JSON 資料放在 WordPress 媒體庫嗎?
A:可以。計算器可從 /wp-content/uploads/ 讀取 coverage.json,但嵌入非 WordPress 檔案時仍建議保持路徑設定清楚,並在部署後測試跨裝置載入。

結論

要在 WordPress 文章中穩定展示獨立工具,關鍵是正確嵌入非 WordPress 檔案並處理樣式隔離。shortcode 適合快速整合,iframe 則適合 coverage_calculator 這類互動式工具。依需求選擇方法、完成檢查清單並測試行動版體驗,就能在保留佈景主題一致性的同時,讓嵌入式內容自然呈現。

woodwood
woodwood

木木,2017 年起寫網誌。喜歡旅行、新科技和小玩意,把見聞與筆記留在這裡——給未來的自己,也給路過的你。