Tangency InWin · 技術評估

三個外掛整合為單一 inwin-plugin 的可行性評估與執行流程

inwin-plugin(早期功能外掛)、inwin-template-plugin(現行樣板外掛)、at-contact-us-plugin(新聯絡我們,僅規格) 收束成一個外掛,並將現行外掛更名為 inwin-plugin。前提是站台正在營運、資料已存在,整合過程不得破壞任何既有關鍵字。

評估日期 2026-07-29 / 依據:三個 repo 全量盤點 + 本地 WordPress 資料庫實測

01結論

先給判斷,再給依據。

可行,而且風險比預期低。但「全部合併」實際上是三件性質完全不同的工作,必須拆開排程,不能當成同一件事做。

  • 合併 inwin-plugin — 真正的合併。工程量遠小於檔案數暗示的規模,功能面幾乎零衝突。低風險
  • 更名為 inwin-plugin — 實質是「接管既有 slug」而非改名,對資料庫最友善的一條路。需維護窗口
  • at-contact-us-plugin不是合併,是從零開發。0 行實作、81 題待確認中 55 題未答、6 個阻塞項。不應綁進本批

三方 identifier 衝突

1

Protype\Library\ 一處,且現在就已在線上打架

需要 schema migration

0

三方皆無自訂資料表,全在 WP 原生表

activation hook 補償邏輯

0

兩邊 activate/deactivate 皆為空方法

新 Contact 未決事項

55

含 6 個開工阻塞項、2 個需外部確認

整合本身會修好一個線上既存缺陷

兩個外掛用完全相同的 PSR-4 mapping 宣告同一組類別,目前由載入順序決定勝負。合併後只剩一份,這個潛伏問題自動消失(詳見關鍵發現 #1)。

02三個 repo 體檢

合併之前,先確認各自到底有多大、裡面有什麼。

項目inwin-plugininwin-template-pluginat-contact-us-plugin
版本0.23.0(線上 0.22.0)0.39.0
PHP 檔/行數54 檔 / 29,167 行227 檔 / 45,301 行0 檔
扣除資料檔後的實際邏輯約 4,400 行約 45,000 行0
功能模組Seller、Contact、Metabox libraryiLayout/iSlot/iWidget/iTemplate/iValue/Product/ProductCategory/ProductCompare/VisualEditor
單元測試2 檔61 檔 / 603 個 test method0
自訂資料表規格指定要建 5–7 張
REST route26 條(inwin-template-plugin/v1未指定
最後 commit2026-04-092026-05-182026-07-28
CI

資料庫現況(本地 inwin_local 實測)

資料數量歸屬
seller CPT564 筆 publishinwin-plugin
seller_type taxonomy163 個 term(三層)inwin-plugin
seller_* post meta各 564 筆inwin-plugin
contact CPT0 筆(但 Admin Columns 設定殘留 → 曾經有)inwin-plugin
itemplate CPT98 筆inwin-template-plugin
itemplate_data_* 動態 meta數百組 keyinwin-template-plugin
引用 iTemplate 系列的 _elementor_data1,194 筆inwin-template-plugin
使用 dynamic tag 的 _elementor_data3,185 筆inwin-template-plugin
自訂資料表0

本地為 2026-03 快照。正式站與 demo1 的 contact 筆數必須另行確認,這決定要不要寫資料遷移(見 Phase 0)。

03六個關鍵發現

會直接改變執行順序的事實,皆經實際讀檔或資料庫/runtime 實測。

#1 線上此刻就存在一個隱性缺陷 —— 而且合併會修好它

兩個外掛的 composer.json 都把 Protype\Library\ 映射到各自的 library/,宣告同一組完整類別名。由 active_plugins 順序決定誰贏,而 inwin-plugin 排在前面。

WP-CLI 實測結果:

Base\Field 實際載入自: .../plugins/inwin-plugin/library/Metabox/Fields/Base/Field.php
有 is_empty_value():     NO
有 apply_default_value(): NO

Gallery\Field 載入自:   .../inwin-template-plugin/library/Metabox/Fields/Gallery/Field.php
Gallery 的父類檔案:     .../plugins/inwin-plugin/library/Metabox/Fields/Base/Field.php

也就是說:template-plugin 自己的 Gallery/Repeater/ColorPicker 等欄位,目前繼承的是 inwin-plugin 的舊版父類,新版的 default 預設值機制與空值判定從來沒有生效過。合併後只剩一份 library,這個問題消失 —— 但同時代表合併會改變既有行為,必須做回歸測試,不能當成純搬移。

#2 inwin-plugin 這個名字已經被佔用,而且正在運作

wp-content/plugins/inwin-plugin/ 是實體目錄(非 symlink),且 active_plugins 同時啟用兩個外掛。所以「更名」在技術上是取代而非改名。好消息是這反而是最安全的路徑:沿用 inwin-plugin/inwin-plugin.php 這個 slug,active_plugins 完全不用動。壞消息是新舊絕不可並存 —— 同名全域函式 activate_inwin_plugin()、同名常數 _INWIN_PLUGIN_* 會直接 fatal。

#3 最硬的一組關鍵字是 Elementor 序列化名,而它們與外掛名稱無關

ilayoutiwidget(document type)、islot_widget(widget)、ivalue-*-tag(dynamic tag)、collect_contact_us(form action)、post-info-plus(widget)—— 這些字串直接序列化在每一筆 _elementor_data JSON 內。只要不主動去碰,更名對它們零影響。反之若有人「順手統一前綴」,全站樣板立刻變成未知元件,且無法自動修復。

#4 collect_contact_us 的失效模式是「靜默」的

這個字串已存在正式頁面的 _elementor_data 裡。若改動它,表單照樣顯示送出成功,但後台再也收不到任何聯絡紀錄,且不會有任何錯誤訊息。注意 Contact.php 註冊時傳的 'contact_action' 只是 registrar key,不是資料庫綁定值,很容易誤判成可以改。

#5 Where-to-Buy 用 term「名稱」當程式判斷依據

前台元件以 $term->name === 'Country' / 'Type' 找根節點,並把 DistributorOnline StoreResellerRetailer ShopSI 這五個 term 名稱直接輸出成前端 tab 的比對值。這 163 個 term 的名稱實質上是不可改的 identifier,合併期間任何 term 整理(包含 WPML 翻譯 term name)都會讓前台直接空白,且沒有 fallback。

#6 三個最典型的合併風險,在這個案子完全不存在

  • activation hook 不再觸發 → 兩邊的 activate()deactivate() 都是空方法,無需補償
  • schema migration → 三方皆無自訂資料表、無 dbDelta、無 cron、無 rewrite rule
  • uninstall 誤刪資料 → 兩邊 uninstall.php 都只有守衛、無清理邏輯,移除外掛不會掉資料

04凍結關鍵字總表

整合過程中一個字都不能動的清單。這張表是「不破壞既有資料」這個前提的具體展開。

A 類 — Elementor 序列化名(最高風險,改了無法自動修復)

類型寫在哪
Document typeilayout iwidget_elementor_template_type postmeta
Widget nameislot_widget post-info-plus_elementor_datawidgetType
Dynamic tag groupivalue-tags iwidget-product-fields_elementor_data__dynamic__
Dynamic tag nameivalue-text-tag ivalue-image-tag ivalue-number-tag ivalue-url-tag ivalue-color-tag ivalue-media-tag ivalue-gallery-tag iwidget-product-description同上
Widget/tag control keyslot_esid slot_id slot_name slot_description value_esid value_id value_name value_group value_desc specified_term_ids specified_term_parent_ids同上
Form actioncollect_contact_us_elementor_datasubmit_actions
表單欄位 label(當成陣列 key)Country / Location Product Type Purpose of contact First Name Last Name E-mail Phone Number No Label private Message Insert線上表單 widget 的 label 文字

B 類 — WordPress 資料綁定

類型
Post typeitemplate seller contact
Taxonomyilayout_category iwidget_category itemplate_category seller_type
Seller post metaseller_address seller_map_url seller_site_url seller_phone seller_email seller_fax
Contact post metacid status privacy location product_type subject first_name last_name email phone message attachment
Contact status 列舉new in-progress resolved closed
iTemplate post metaitemplate_esid ilayout_esid iwidget_esid itemplate_settings_main_en(含 region/locale 變體)itemplate_data_{id}_{region}_{locale} itemplate_id itemplate_type {itemplate,ilayout,iwidget}-{title,description,image} iwidget-injection iwidget-expand-options
Product 系列 meta_product_spec _product_spec_tablepress_id _product_image_gallery _product_{field}_{locale} _inwin_product_hidden_visibility product-{features,overview,specifications}-*
Term meta_product_category_image_gallery _product_category_description _product_category_{field}_{locale} is_hidden
User meta_inwin_compare_list
Optionsinwin_enable_ilayout inwin_enable_iwidget inwin_enable_itemplate inwin_admin_per_page inwin_admin_thumbnail_size inwin_import_seller_data_250226
Shortcodeinwin_where_to_buy inwin_compare_button inwin_product_compare
ESID 前綴itemplate- ilayout- islot- iwidget- ivalue-
自訂 hook(對外承諾)inwin_contact_form_submitted inwin_product_compare_visible_ids
Seller term 名稱Country Type + 5 個 sales type + 9 個產品線 + 107 個國家名

C 類 — 使用者端持久值(伺服器改不到,只能沿用)

類型存活期
Cookieinwin_region30 天
localStorageinwin_compare_list inwin_auto_save_enabled永久(至使用者清除)
JS 全域物件inwinWtbData頁面生命週期

05命名與目錄策略

這是整個計畫的核心決策,其他步驟都由它推導出來。

最終落點

wp-content/plugins/
  └── inwin-plugin/                    ← 合併後的唯一外掛(接管舊 slug)
        ├── inwin-plugin.php            ← Plugin Name: Tangency InWin Plugin
        ├── includes/                   ← 骨架(採 template-plugin 版)
        ├── library/                    ← Protype\Library 只留一份(採 template-plugin 版)
        └── modules/
              ├── iLayout/ iSlot/ iWidget/ iTemplate/ iValue/
              ├── Product/ ProductCategory/ ProductCompare/ VisualEditor/
              ├── Seller/               ← 自 inwin-plugin 移入(目錄層級必須維持兩層)
              └── Contact/              ← 自 inwin-plugin 移入(暫時原樣,待 Phase 5 汰換)

為什麼是「接管 slug」而不是「改名」

active_plugins 這個 option 存的是 目錄/主檔.php。既有值裡本來就有 inwin-plugin/inwin-plugin.php,讓合併後的外掛落在這個路徑,這筆設定完全不用動,也不需要任何資料庫層面的補償。要處理的只是移除 inwin-template-plugin/… 那一筆。

改與不改的三分法

項目處理理由
外掛目錄名、主檔名必須改更名的本體
6 處硬編碼主檔名的 plugins_url()必須改漏改的症狀是「靜默的資源 404」,最容易漏
常數 _INWIN_TEMPLATE_PLUGIN_*必須改與被取代的舊外掛常數同名,須統一為 _INWIN_PLUGIN_*
全域 class/函式 inwin_template_plugin*必須改僅 6 個檔案,成本低;避免與舊外掛殘留衝突
根目錄 .gitignore必須改現有規則全寫成 inwin-plugin/…(歷史化石),目前失效、更名後會突然生效並排除掉 composer.lock
PSR-4 namespace inwin_template_plugin\建議不改452 處、200+ 檔;不寫進資料庫;唯一 runtime 字串組裝點只有一行。風險遠大於收益
Text domain(690 處)建議不改目前只有 .pot、無任何 .mo,改與不改都不影響顯示
REST namespace inwin-template-plugin/v1建議不改26 條路由 + 3 支前端 JS 硬編碼;改動只有壞處
後台選單 slug inwin-templates建議不改站上裝了 Admin Menu Editor,其排序設定綁這個 slug
A/B/C 三類凍結關鍵字絕對不動見上一節

刻意接受的取捨

採用上述策略後,外掛叫 inwin-plugin,但內部命名空間、text domain、REST namespace、後台選單 slug 仍然叫 inwin_template_plugin / inwin-templates。這個不一致是刻意換來的安全性。若日後要統一,應該是一個單獨的、不夾帶任何功能變更的 PR,並以 603 個既有單元測試當防護網。

06執行流程

六個階段。Phase 0–4 是一條連續的路徑,Phase 5 應獨立立案。

PHASE 0前置盤查與備份必須在 air-2019 執行

mlab 連不到 demo1(ssh 無法解析),remote-* 系列 CLI 也不在 mlab。以下步驟一律從 air-2019 執行。

P0-1正式站/demo1 資料盤點

這一步的產出直接決定 Phase 5 要不要寫資料遷移,以及切換窗口需要多長。

remote-wp cli "post list --post_type=contact --post_status=any --format=count"
remote-wp cli "post list --post_type=seller  --post_status=any --format=count"
remote-wp cli "option get active_plugins --format=json"
remote-wp cli "db query \"SELECT COUNT(*) FROM wp_postmeta
  WHERE meta_key='_elementor_data' AND meta_value LIKE '%collect_contact_us%'\""
remote-wp cli "db query \"SELECT COUNT(*) FROM wp_postmeta
  WHERE meta_key='_elementor_data' AND meta_value LIKE '%post-info-plus%'\""
remote-wp cli "db query \"SELECT COUNT(*) FROM wp_posts
  WHERE post_content LIKE '%inwin_where_to_buy%'\""

驗收:一張表列出 contact/seller 筆數、使用 collect_contact_uspost-info-plus 的頁面數、含 WTB shortcode 的頁面數。

P0-2完整備份

資料庫全量 dump + wp-content/plugins/ 打包。這是唯一的 rollback 依據。

驗收:備份檔可在本地還原並開得起來。

P0-3決策拍板

把「待拍板」一節的 5 個決策點結掉,特別是 D5(Contact 是否納入本批)。

驗收:決策記錄寫進 docs/plans/

PHASE 1Library 統一唯一會改變線上行為的一步

先做這一步,因為它是整個計畫中唯一「合併本身就會改變行為」的部分(見關鍵發現 #1)。把它單獨隔離出來,行為變化才追得清楚。

T1-1建立現況特徵測試

在動任何程式碼之前,先把目前(舊版父類生效下)的儲存/讀取行為寫成測試並讓它通過。這組測試的作用是量化「合併會改變什麼」。

  • 重點差異:default 預設值機制、is_empty_value() 的空值判定、Select 新增的 sanitize_text_field、空值改走 delete_meta

驗收:測試綠燈,且能明確指出哪些欄位行為會變。

T1-2以 template-plugin 版取代,只留一份 library

template-plugin 版是嚴格超集(多出 Checkbox/ColorPicker/Gallery/Radio/Repeater/Unique 六種欄位型別)。

驗收:composer8.0 test:unit 全綠(603 個 test method)。

T1-3Metabox 回歸測試

針對 seller-info(6 欄位)與 contact-history(12 欄位)兩個 metabox 做實際存檔驗證,確認 meta 值與改動前一致。

驗收:存檔前後 wp_postmeta 逐欄位比對無非預期差異;有差異者需為 T1-1 已預期並記錄的項目。

PHASE 2模組移植不改動任何 identifier
T2-1Seller 模組移入

五個檔案 + assets 整組移入 modules/Seller/,namespace 由 inwin_plugin\Module\Seller 改為 inwin_template_plugin\Module\Seller,主 class 加一行註冊。

  • 目錄層級必須維持兩層 —— WhereToBuyShortcode.phpplugin_dir_url(dirname(dirname(__FILE__))) 推導資源路徑,放深一層就整組 404,前台清單直接空白
  • 凍結:CPT seller、taxonomy seller_type、6 個 meta key、shortcode inwin_where_to_buy、handle inwin-wtb、JS 全域 inwinWtbData、CSS class inwin-wtb__*、以及所有 term 名稱

驗收:停用舊外掛後,後台 564 筆 seller 完整、前台 WTB 篩選/tab/無限捲動全部正常。

T2-2Contact 模組原樣移入

三個檔案 497 行,只有 4 個外部耦合點。本階段刻意不重寫 —— 它即將在 Phase 5 被取代,移植的唯一目的是不中斷服務,最小改動最合理。

  • 凍結:CPT contact、12 個 meta key、4 個 status 值、collect_contact_us、10 個 Elementor 欄位 label、CID 格式 CN{Ymd}{post_id:04d}、hook inwin_contact_form_submitted、metabox id contact-history
  • 已知技術債(本期不動、明確記錄):add_form_action() 在 Elementor Pro 3.5+ 已 deprecated

驗收:從 Elementor 表單實際送出一筆,後台出現對應紀錄,12 個 meta 值格式與舊版逐欄位一致。

T2-3post-info-plus widget 移入 + 補守衛

移入時補上 class_exists 守衛。這是修 bug 不是重構 —— 現況在「只裝 Elementor 免費版、沒有 Pro」的環境會直接 fatal。

驗收:停用 Elementor Pro 後站台仍可正常載入。

T2-4死碼清除
  • common/snippets/ 一次性匯入工具 —— 每個 request 都在載入 917 KB 的 import-data.php,而匯入任務早在 2025-02 完成。這是本次最直接的效能收穫
  • common/woodmart/ 的 require —— 目錄根本不存在,只因 hook 被註解掉才沒 fatal
  • commonadminpublic 空殼骨架 —— 這 6 個資產檔因為把檔案系統路徑當 URL 傳,從來沒有真正載入過
  • 空 class PostModelPostModelFields、4 個 sample-*.json
  • wp-tests-config-remote.php —— 含遠端資料庫名稱與帳號且已進版控,不應帶進新外掛

驗收:移除後全站功能無異動;option inwin_import_seller_data_250226 保留在資料庫(無害,不需清)。

T2-5測試套件合併

兩邊 autoload-dev 都用 Tests\ 前綴,WP mock function 也各有一套,重複宣告會是合併後的第一批紅燈。

驗收:composer8.0 test:unit 全綠。

PHASE 3更名純機械改動,可完全依賴測試
T3-1目錄與主檔更名

inwin-template-plugin/inwin-plugin/,主檔同步更名,Plugin Header 的 Name 改為 📦 Tangency InWin Plugin

T3-26 處硬編碼主檔名修正

已定位完成:iWidget.php:197,204,213iLayout.php:200,207ProductCompare.php:39

驗收:後台三個管理頁的 CSS/JS 與比較功能資源皆 200,DevTools Network 無 404。

T3-3常數與全域符號改名

_INWIN_TEMPLATE_PLUGIN_*_INWIN_PLUGIN_*(約 40 處),includes/ 下 6 個全域 class 與 3 個全域函式同步改名(含檔名)。

T3-4.gitignore 修復

現有規則是「這個 repo 曾經叫 inwin-plugin」留下的化石,目前失效,更名後會突然生效並把已追蹤的 composer.lockpackage.json 排除掉。更名 PR 必須同時修它。

T3-5Gitea repo 處理

Gitea 上 Tangency/inwin-plugin 已存在,直接改名會撞。順序:舊 repo 先改名封存(如 inwin-plugin-legacy),再把 inwin-template-plugin 改名為 inwin-plugin,最後更新本地 remote。

T3-6文件與工具鏈同步

CLAUDE.mddocs/commands/remote-* 指令說明中的路徑。

驗收:本地 symlink 重建 + 強制清 PHP 8.0 opcache(opcache 是 inode-based,切 symlink 不會自動失效),全站功能清單逐項通過。

PHASE 4正式切換需要維護窗口

為什麼一定要維護窗口

合併版與舊 inwin-template-plugin 不能同時啟用(會重複註冊 itemplate CPT 與 islot_widget),與舊 inwin-plugin 也不能並存(同名全域函式與常數直接 fatal)。因此切換必須是原子操作,中間有一段短暫的「兩者皆停用」。

# 1. 備份(再做一次,取最新狀態)
# 2. 開啟維護模式
wp plugin deactivate inwin-template-plugin inwin-plugin
# 3. 實體刪除兩個舊目錄(必做 —— 留著會被誤啟用,導致雙重註冊)
# 4. 部署合併版到 wp-content/plugins/inwin-plugin/
wp plugin activate inwin-plugin
# 5. 強制清 PHP 8.0 opcache
# 6. 關閉維護模式 → 執行驗證清單

Rollback 條件:驗證清單任一項失敗且 15 分鐘內無法定位 → 還原備份的 plugins/ 目錄與 active_plugins option。因為沒有任何 schema 變更,rollback 不需要處理資料。

PHASE 5Contact 汰換獨立立案,不綁本批

為什麼建議切開

  • at-contact-us-plugin 0 行實作,這是從零開發不是合併
  • 81 題待確認中 55 題未答,含 6 個開工阻塞項
  • 2 個問題必須先向外部確認:正式站前面有無 CDN/反向代理(決定 IP 取得方式,處理錯誤會導致「封鎖一筆垃圾訊息就封掉全站」)、主機是 Apache 還是 Nginx(決定附件目錄防護方式)
  • 規格明確選擇 custom table,而現行外掛完全沒有自訂資料表先例 —— 等於要在此外掛首次建立 $wpdbdbDelta + schema 版本管理規範
  • 規格中完全沒有提到既有 contact CPT 資料的遷移(所有文件的「舊站」都是指 Laravel 舊站,不是現行 WordPress 站)

好消息:命名幾乎全部留白等定案。規格作者已明文寫「配合 Wake 規劃 —— 三個外掛收束成一個」,plugin slug/class prefix/text domain/常數/namespace/資料表名/option key 全部未指定。真正鎖死的只有 4 項:shortcode [at_contact_form] / [at_contact_records]、CSS 前綴 at-、Email 模板路徑、10 個 WPML 語系碼。

另有兩個必須先解的落差:規格假設 PHP 8.2,而本專案強制 PHP 8.0(不可用 enum 等);規格用 WPML 原生語系碼(zh-hantja),而本專案用內部 4 字元碼(hantjapn)。

建議順序:R1 規格收斂(先解 6 個阻塞項與 4 個內部矛盾)→ R2 正式站 contact 資料盤點 → R3 建立本外掛的 DB migration 規範 → R4 ContactUs 模組開發 → R5 資料遷移 → R6 前台由 Elementor 表單切換為 shortcode(需頁面端配合)→ R7 舊 Contact 模組下線。

07待拍板決策

每一項都附建議。若無異議,即依建議執行。

#決策建議理由
D1 PSR-4 namespace inwin_template_plugin\ 要不要一併改成 inwin_plugin\ 不改 452 處、200+ 檔的機械改動,不寫進資料庫、無實質收益。若要做,應是單獨 PR 且不夾帶任何功能變更
D2 Text domain(690 處)要不要改? 不改 目前只有 .pot、無 .mo,介面靠原始字串顯示,改了沒有任何可見效果
D3 REST namespace inwin-template-plugin/v1 要不要改? 不改 26 條路由 + 3 支前端 JS 硬編碼;改動只會打斷既有整合與快取
D4 Contact 模組移植時要不要順手修 deprecated 的 add_form_action() 不修,記錄待辦 符合外科手術原則;且該模組即將在 Phase 5 被整個取代,投資在此不划算
D5 at-contact-us 是否納入本批? 不納入 0 行實作、55 題未答、2 個需外部確認的環境問題。綁進來會讓一個低風險合併變成高風險長專案

08風險登記簿

風險等級失效表現控制措施
誤改 Elementor 序列化名 極高 全站樣板變成未知元件、白畫面,且無法自動修復 凍結清單 A 類納入 PR 檢查項;code review 明列「本 PR 未觸碰任何 A 類關鍵字」
改動 collect_contact_us 極高 靜默失敗 —— 表單顯示成功但後台永遠收不到 移植後必須實際送出一筆做端到端驗證,不能只看程式碼
新舊外掛短暫並存 同名函式/常數 fatal,或 CPT/widget 重複註冊 切換設計為原子操作;舊目錄實體刪除而非僅停用
Library 統一造成行為變化 metabox 欄位的預設值/空值儲存行為改變 Phase 1 獨立進行,先寫特徵測試量化差異,再做 18 個欄位的存檔回歸
Seller 模組放錯目錄層級 WTB 前台 CSS/JS 全 404,清單完全空白 維持 modules/Seller/ 兩層結構;驗收含前台實際操作
漏改硬編碼主檔名 後台資源靜默 404,管理頁樣式跑掉 6 處已全數定位;驗收看 DevTools Network
opcache 未清 切換後仍執行舊程式碼,症狀難以理解 PHP 8.0 isolate FPM 不會被 herd restart 重啟,須以臨時 mu-plugin 強制 opcache_reset()
Seller term 名稱被更動 Where-to-Buy 前台直接空白,無 fallback 整合期間凍結所有 term 編輯與 WPML term 翻譯操作
正式站 contact 已有資料 未知 Phase 5 汰換時歷史案件遺失 P0-1 必須先確認;本地為 0 筆但 Admin Columns 設定殘留顯示曾經有過

09切換後驗證清單

每一項都要實際操作,不接受「看起來沒問題」。

外掛層

  • active_plugins 只剩 inwin-plugin/inwin-plugin.php,無失效條目
  • 後台外掛列表無「外掛檔案不存在」警告
  • debug.log 無 fatal/warning/deprecated 新增

樣板系統(最高風險區)

  • 隨機開 5 個使用 iLayout 的頁面,元件正常渲染,無「未知元件」
  • Elementor 編輯器開啟一個 iLayout,islot_widget 正常顯示且可編輯
  • Dynamic tag 下拉可見 ivalue-* 全系列,選取後正常取值
  • VisualEditor(admin.php?page=visual-editor)可開啟且能存檔
  • 商品比較功能:加入、底欄、比較頁規格表合併皆正常

移入的模組

  • 後台 seller 列表 564 筆完整,隨機開一筆確認 6 個欄位值正確
  • 前台 Where-to-Buy:國家篩選、產品線篩選、銷售類型 tab、無限捲動
  • Elementor 表單實際送出一筆 → 後台出現紀錄 → 12 個 meta 值格式正確
  • 使用 post-info-plus widget 的頁面正常顯示

多語系與資源

  • 切換語系後商品/分類翻譯正常(WPML 僅作為語系訊號源)
  • DevTools Network 全站無 404(特別是後台三個管理頁)
  • REST inwin-template-plugin/v1 各端點回應正常