Files
2meet-data-optimizer/CHANGELOG.md
wpdev 9fa84845be fix: NinjaFirewall 相容性 — 保護 WAF 設定選項不被重導向
評估 NinjaFirewall (WP Edition) 4.9 的相容性,結論是兩者可共存且
不需要開發 AddOn(該外掛全 codebase 零個 apply_filters('nfw_*') /
do_action('nfw_*'),官方相容手段全在部署層)。但核心有一個隱患必須補。

TMDO_Options_Manager::register_settings_group() 以 pre_update_option_{key}
回傳 $old_value,讓選項不再落地 wp_options、改存專屬設定表。而
NinjaFirewall 的 Full WAF 走 auto_prepend_file,在 WordPress 載入前就以
原生 mysqli 直查 wp_options 取 nfw_options / nfw_rules。一旦這些鍵被
重導向,WAF 會讀不到設定而靜默停止防護 —— 不報錯、不寫 log。

nfw_rules 約 77KB 且 autoload=auto,正是 autoload 瘦身最誘人的目標,
因此這條路徑並非理論風險。

Added
- PROTECTED_OPTIONS 常數與註冊守衛(nfw_options / nfw_rules / nfw_checked),
  命中時發出 _doing_it_wrong()。守衛置於方法開頭,全部鍵都被擋時提前返回,
  不再建立空的設定表。
- tests/unit/OptionsManagerProtectedTest.php(4 tests / 10 assertions),
  鎖住「受保護鍵絕不會被掛上 pre_option_* / pre_update_option_* 攔截」。
- docs/WAF-COMPATIBILITY.md:模式差異、symlink 多租戶部署、WP SaaS 開站
  流程與驗證清單、三條開發約束、實測風險矩陣。

Changed
- Migration Wizard 輪詢 500ms → 2s,與四個 stress-test 面板一致。
  原本 2 req/s 打同一 REST endpoint,易觸發 WAF rate-limit 與 bot 偵測。

autoload 最佳化不受影響:optimize_autoload() 只改 autoload 欄位、不刪列,
而 Full WAF 的 SELECT * 不看 autoload。

驗證:591 tests / 1166 assertions 通過,PHPCS 零違規,版本一致性 1.0.2。
dev30 於 Full WAF 與 WP WAF 兩種模式下實測,firewall log 中 TMDO 相關
攔截 0 筆。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SdjXAU473eekjPBB8vPVRS
2026-08-15 20:38:09 +08:00

269 lines
13 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Changelog
All notable changes to this plugin will be documented here.
Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
Versioning follows [Semantic Versioning](https://semver.org/).
---
## [1.0.2] — 2026-08-15 — NinjaFirewall 相容性:WAF 設定選項保護
**性質**:防禦性修正 + 文件。無 schema 變更,無破壞性變更。
### Added
- **`docs/WAF-COMPATIBILITY.md`** — NinjaFirewall (WP Edition) 4.9 相容性評估
結論:兩者可共存,**不需要開發 AddOn**NinjaFirewall 全 codebase 零個
`apply_filters('nfw_*')` / `do_action('nfw_*')`,官方相容手段全在部署層)。
文件涵蓋 WP WAF 與 Full WAF 的模式差異、symlink 多租戶部署的必要設定、
三條開發約束,以及實測風險矩陣。
- **`TMDO_Options_Manager::PROTECTED_OPTIONS`** 常數與註冊守衛
`modules/options/class-tmdo-options-manager.php`
`register_settings_group()` 會以 `pre_update_option_{key}` 回傳 `$old_value`
讓選項不再落地 `wp_options`、改存專屬設定表。但 NinjaFirewall 的 Full WAF 走
`auto_prepend_file`,在 WordPress 載入前就以**原生 mysqli 直查 `wp_options`**
`nfw_options` / `nfw_rules`。一旦這些鍵被重導向,WAF 會讀不到設定而
**靜默停止防護 —— 不報錯、不寫 log**
現以 `PROTECTED_OPTIONS``nfw_options` / `nfw_rules` / `nfw_checked`)在註冊
階段擋下,並發出 `_doing_it_wrong()`。守衛置於方法開頭,全部鍵都被擋時提前
返回,不再建立空的設定表。
註:autoload 最佳化不受影響 —— `optimize_autoload()` 只改 `autoload` 欄位、
不刪列,而該處的 `SELECT *` 不看 autoload。
- **`tests/unit/OptionsManagerProtectedTest.php`** — 4 tests / 10 assertions
鎖住「受保護鍵絕不會被掛上 `pre_option_*` / `pre_update_option_*` 攔截」這個
核心保證,並驗證全數受保護時不對資料庫發出查詢。
### Changed
- **Migration Wizard 輪詢間隔 500ms → 2s**`admin/assets/wpdo-migration-wizard.js`
原本 2 req/s 打同一個 REST endpoint,容易觸發 WAF 的 rate-limit 與 bot 偵測。
改為 2 秒,與四個 stress-test 面板既有的輪詢節奏一致。
---
## [1.0.1] — 2026-08-08 — Schema Registry 冪等性修正(cold zone 欄位重複累積)
**性質**:核心 bug 修復。無 schema 變更,無 API 變更,無破壞性變更。
### Fixed
- **`TMDO_Schema_Registry::register()` 的 cold zone 分支會無限累積重複項**
`includes/class-tmdo-schema-registry.php`
三個 zone 索引的寫入方式並不一致:
- `hot``$this->hot_columns[$post_type][$column] = ...`(以 column 為 key,天生冪等)
- `warm``$this->warm_fields[$meta_key] = ...`(以 meta_key 為 key,天生冪等)
- `cold``$this->cold_fields[$post_type][] = ...`**append,無去重**
`wpdo_register_fields` 本來就會被觸發多次——核心自身在 `plugins_loaded:4` 觸發,
主檔另有 late-bind safety net 於 `plugins_loaded:30` 再次觸發,好讓在 `:6` 之後才
bootstrap 的 AddOn 也能趕上;再加上主外掛與其 AddOn 可能同時註冊同一批欄位。
**實測影響**:某站台 `cold_fields['hp_vendor']` 累積到 **35 筆但只有 9 個相異值**
每個 key 重複 4 次。修正後為 9 筆、零重複。
修法:cold 分支加入 `in_array( ..., true )` 去重,使 `register()` 對同一
`(post_type, meta_key)` 成為冪等操作,與 hot / warm 的既有行為一致。
### 驗證
- 核心單元測試 **587 tests / 1156 assertions** 全綠
- `wp wpdo doctor` 於兩個站台皆 0 FAIL
- Version bump 1.0.0 → 1.0.12 點一致:header / `TMDO_VERSION`
---
## [1.0.0] — 2026-07-31 — 取代 wp-data-optimizer v3.4.6
本版把 `wp-data-optimizer` v3.0.1v3.4.692 個 commit)全數 backport 進來,
`wp-data-optimizer` 自此退休:兩個站台皆已停用它,本機目錄改名為
`wp-data-optimizer.retired`,其 git 歷史保留在 gitea。
### 🔒 Security / 正確性
- **7 處 `Logger::error()` 參數不足**array 傳給 string `$hook`)修正 —— 4 個 stress
tester、auto-promoter、conflict-detector、hook-bus,皆為 TypeError fatal
- **`Logger::trace_id()` 補回**`Audit_Logger::write_row()` 一直呼叫它,但提煉時漏了;
`Audit_Logger::init()` 從未註冊所以隱藏至今 —— 實機驗證才暴露
- REST 4 個公開端點加上 `show_in_rest` 欄位 allowlistCVSS 5.3
- 13 個破壞性 admin 動作由 GET 改 POST + nonce
- DDL 型別白名單(19 型別)、CLI 表名守衛
- 整欄清空改 `wpdo_allow_mass_column_clear` opt-in(原本 >500 列才擋)
- audit 表補 `group_name` / `action` 欄並註冊 `Audit_Logger::init()`
- `known_login_ips` 註冊(spoke-sso 實際寫入的欄位,先前落 `wp_usermeta`
### ⚡ 並發
- warm 表 `UNIQUE KEY ui_post_meta`(缺它 `ON DUPLICATE KEY UPDATE` 不生效)
- Zone_Cold 改 `JSON_MERGE_PATCH` / `JSON_REMOVE`、Zone_Warm 原子 `increment()`
hook-bus `write_to_flat` 改 upsert
### 🏗 架構
- 回填 `TMDO_Zone_Router` + `TMDO_Routing_Predicate`Sync_Bridge 400→269 行)
- 回填 Migration Phase Strategyinterface + base + 11 個 phase 類別,
orchestrator 1107→640 行,公開介面不變
- 核心新增 `TMDO_Standard_Post_Interceptor`HP AddOn 4 個 interceptor 573→344 行
### 🔌 相容性
- hook 橋改**雙向**:核心一律 `do_action('wpdo_*')`,原本單向轉發使所有
`tmdo_*` 契約收不到事件
- 57 個 AddOn 類別補 `WPDO_*` alias(核心 alias 表在 `plugins_loaded:4` 執行,
涵蓋不到 `:6` 才載入的 AddOn
- 38 個 CLI 子指令補 `wp tmdo` 命名空間
- 選單 slug 統一回 `wp-data-optimizer`(B 內部 10+ 處連結本來就指向它)
- HP adapter 介面改為 `TMDO_ extends WPDO_`,讓 `instanceof WPDO_HivePress_Adapter` 成立
### 🖥 Admin
- Settings 七個分區各加「儲存此區塊」AJAX 存檔(`wp_ajax_wpdo_save_settings_section`
+ 7 個 `save_section_*()` + `admin/assets/wpdo-settings.js`),整頁送出仍可用
- inline `style=` 由 348 處降到 9 處(剩下的全是 `--wpdo-*` CSS custom property
載體);`wpdo-admin.css` 543 → 912 行,補 149 個 class
### 🚧 邊界
- 核心不再無守衛呼叫 AddOn 類別。`TMDO_Listing_Stats`HivePress AddOn)先前
在 admin Dashboard、兩個公開 REST 端點、`wp tmdo cleanup --archive-expired`
被直呼,沒裝該 AddOn 的站台會 fatal`TMDO_HPCT_Import` 在 admin 與
`wp tmdo import-hpct` 同樣缺守衛
- `TMDO_Zone_Warm::VIEW_KEY` / `VIEW_TTL` 由核心持有(值與 AddOn 常數相同的
`'wpdo_views'`,指向同一批列,無資料遷移)
- 新增 `CoreBoundaryTest`:靜態掃描 126 個核心生產檔,強制每處 AddOn 類別
呼叫都在同一函式內有 `class_exists()` 守衛
### ✅ 品質
- 128 個生產檔 `declare(strict_types=1)`
- PHPCS 0 errors / PHPStan level 6baseline 710
- 測試:核心 unit 587 / integration 416、hivepress-addon unit 154 /
integration 57、woocommerce-addon unit 10 / integration 18
- gitea CI:核心 6 個 job 全綠 + 11 個 AddOn workflow + branch protection
- 打包 10 項終檢全 PASS569 KB / 187 entriesschema drift 034 CREATE / 34 DROP
### ⚠️ ABI / 行為變更
- `doctor_callback` 由 3 參數改為 1 參數(表名)
- `wpdo_capture_before_value` 預設 `true``false`;需要 `value_before`
消費者(audit log)要 `add_filter( 'wpdo_capture_before_value', '__return_true' )`
- `wpdo_allow_mass_column_clear` 現為 opt-in,整欄清空預設被拒
- `SCHEMA_VERSION` 2.0.0 → 2.1.0audit 表 ALTER
---
## [0.1.0] — 2026-05-15 (initial release, Phase 0-5 完成)
### Phase 5 hotfix(同日完成)
-`TMDO_WooCommerce::doctor_check()` callback signature mismatchcli/class-tmdo-cli.php:264 改 call_user_func 傳 3 參數)
-`includes/back-compat/trait-wpdo-anti-eav-aware-alias.php` — trait + interface 反向相容(PHP class_alias 不支援 trait/interface
- `WPDO_Anti_EAV_Aware` trait wrapper 可讓 2meet-brandcards 等 sister plugin 直接 `use`
- `WPDO_Entity_Adapter_Interface` extends `TMDO_Entity_Adapter_Interface`
- 完整 `uninstall.php`(核心 244 行從 wp-data-optimizer 提煉,34 張表 DROP TABLE 對齊)
- HP AddOn + infocards AddOn `uninstall.php` 補 schema drift check 對齊
- **12 plugin ZIP 全通過 10 終檢**
### 12 ZIP 交付(dist/
| Plugin | Size | MD5 |
|---|---:|---|
| 2meet-data-optimizer | 521 KB | a10bb191e662cb5fb53a3d23165c71e5 |
| -hivepress-addon | 117 KB | 24bd8c3211421fed86dc551658d7064a |
| -woocommerce-addon | 34 KB | fbd6f60368fc93310f2e90e58c95b53c |
| -spoke-addon | 24 KB | c1e92b755fb1d108a141086ccf1fe519 |
| -hub-addon | 22 KB | 4e010c63ed8ad1dd24f06b8741e3a1b0 |
| -infocards-addon | 22 KB | 7f095fdc4748d3ff4cd4e05f1bf3d417 |
| -latepoint-addon | 21 KB | 60eeb4ea67cdc996cb60b6ad7126f2df |
| -bookings-addon | 21 KB | ac32b85d84e912d3b5a1cdfb56f9fa96 |
| -mobile-bridge-addon | 20 KB | 59905719cfee4bd31967736517391a43 |
| -collab-addon | 20 KB | 1ed0a2983a692a94b6c42f21b62af2c2 |
| -quotation-addon | 20 KB | 5e693a4df3ce48de447cf6277deaece5 |
| -playlist-addon | 20 KB | d52552782f383abbe8f278a5b85cafef |
### CLI smoke test12 指令 全 PASS
- `wp tmdo status / doctor / analyze / install / cleanup / health-snapshot / site-metrics / benchmark`
- `wp wpdo status / doctor` (alias 路徑)
- `wp tmdo spoke-sync --dry-run` / `wp tmdo spoke-force-logout --user-id=1 --dry-run`
---
## [0.1.0] — 2026-05-15 (initial release, Phase 0-4 完成)
### Added — 核心反 EAV 引擎(從 wp-data-optimizer v2.16.0 提煉)
- 4 Zone 分流(Hot / Warm / Cold / Archive+ Sync Bridge 雙寫
- 7 態 FSM 模組生命週期(idle → dual_write → backfill → verify → cutover → cleanup → complete
- 4 entity 通用引擎(post / user / term / comment+ Hook Bus + Mode Manager
- Query Router (`pre_get_posts` 改寫) + Query Compiler
- Migration Engine + Orchestrator + Backfill + Stress Tester + Shadow Verifier
- Snapshot / Safety / Diagnostic / Notifications (Email / Slack / Discord / Telegram)
- Crypto AES-256-GCM AEAD + Safe Unserialize
- WP-CLI 18+ subcommand
- Admin Dashboard + KPI Hero + Tab Groups + Setup Wizard + Help Tabs
### Added — 對外向後相容
- `TMDO_*` 類別 + `class_alias` 80+ 個 → 對外保留 `WPDO_*` 類別名
- 8 個常數 alias`WPDO_VERSION` / `WPDO_PLUGIN_DIR` / `WPDO_TABLE_PREFIX` 等)
- 9 個 hook dual-fire 橋接(`tmdo_register_fields``wpdo_register_fields` 等)
- WP-CLI 雙命名空間:`wp tmdo` (主) + `wp wpdo` (alias)
### Removed — 整合層搬出
- HivePress + 12 擴充整合(13 adapter + 7 interceptor + 5 query interceptor + bootstrap + admin + CLI)→ 搬到 `2meet-data-optimizer-hivepress-addon`
- WooCommerce 整合 → `2meet-data-optimizer-woocommerce-addon`
- LatePoint 整合 → `2meet-data-optimizer-latepoint-addon`
- 2meet-infocards / bookings / quotation / mobile-bridge / collab / playlist 整合 → 各自 6 個 AddOn
- Hub-core SSO group 與自訂表註冊 → `2meet-data-optimizer-hub-addon`
- Spoke-sso SSO group 與 CLI → `2meet-data-optimizer-spoke-addon`
- `TMDO_Core::register_hivepress_defaults()` (193 行) → HP AddOn
### Migration from `wp-data-optimizer v2.16.0`
- `wp_wpdo_*` 表結構完全相容(不 rename,新外掛沿用既有 schema
- 舊外掛先停用即可改用新外掛接管
- 兩外掛**互斥**:本外掛偵測舊外掛仍 active 時會發 admin noticeplan §8.1
### Limitations / Known issues (Phase 5 follow-up)
- `tests/` 目錄空殼,PHPUnit unit + integration tests 需後續搬遷
- `phpcs.xml.dist` 缺;`composer install --dev` 後可手動跑
- WP 6.5+ `Requires Plugins:` 強制 Plugin Name 比對;hub-core / spoke-sso 仍寫死 `wp-data-optimizer`,需更新或本 plugin 加偽 `Plugin Name: WP Data Optimizer` alias headerPhase 5
- `TMDO_WooCommerce::doctor_check()` signature 與 Custom_Table_Registry callback 不對齊(warning level
- Trait `Trait_TMDO_Anti_EAV_Aware` 暫無 alias wrapperclass_alias 不適用 trait
### Phase 0-4 統計
- **PHP files**: 203(核心 111 + Hub 5 + Spoke 7 + HP 47 + WC 8 + LP 5 + 6 family 各 5
- **PHP lint**: 全 PASS
- **Plugin active**: 12/12
- **Custom tables registered**: 14Hub 12 + Spoke 2,未含 6 family no-op
- **SSO group fields**: 7
- **Schema fields**: 23 (Hot 20 + Cold 3HP 未安裝 → HP fields no-op)
---
## 來源外掛累計重要 release(供考古)
詳見 `/var/www/Studio/wp-local-dev30/wp-content/plugins/wp-data-optimizer/CHANGELOG.md``CLAUDE.md`v2.0.0 → v2.16.0 共 47 次發版的累計改動。
亮點:
- v2.6.4 H-4 加密 webhook 密鑰
- v2.13.3 audit 7/7 finding 全清零
- v2.15.0 AES-256-CBC → AES-256-GCM AEAD
- v2.16.0 UI/UX KPI Hero + Grouped Tab Navigation
---
## [Unreleased]
### Phase 5 候補
- Tests 套件搬遷
- PHPCS 套件 + 0/0 達成
- 打包腳本 10 終檢驗收
- WPDO_ → TMDO_ migration CLI