Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TbG1keQQ7XBa7qMQY16KCY
19 KiB
PLAN — 2meet Data Optimizer (核心)
完整四階段拆分計畫見
~/.claude/plans/wp-data-optimizer-2meet-data-optimizer-zesty-liskov.md
Current state
- Version: 0.1.0 (scaffold + 4 phase 完成 2026-05-15)
- Phase: 全 4 phase 已完成
- Source: 從
wp-data-optimizer v2.16.0提煉
Phase 0 ✅ — 骨架建立 (2026-05-15)
- 12 plugin 目錄結構(核心 + 11 AddOn)
- 主檔
2meet-data-optimizer.php+ Plugin Header includes/class-tmdo-bootstrap.phpstubuninstall.phpstubcomposer.json.gitignore- 7 件 MD(README / PLAN / CHANGELOG / DEPLOY / SECURITY / DESIGN / CLAUDE)
Phase 1 ✅ — Core v0.1.0 (2026-05-15)
- rsync 從 wp-data-optimizer 複製 ~110 個核心檔案,排除 HP/WC/LP/2meet 整合
- 檔名
class-wpdo-*→class-tmdo-*(含 abstract / interface / trait) - sed 內容批次 rename:
WPDO_→TMDO_(class + 常數,hook/table/option 前綴wpdo_保留共用) - 常數
TMDO_PLUGIN_DIR→TMDO_PATH等對齊 - Text-domain
'wp-data-optimizer'→'2meet-data-optimizer' - 主檔重寫成完整 loader(require chain ~150 行)
- 加
tmdo_run()boot 函式 +plugins_loaded:4action - 加
late-bind safety net(priority 30) 確保 AddOn listener 收到 hook - 加
includes/class-tmdo-back-compat.php— 80+ class_alias + 8 常數 alias + 9 hook dual-fire - 移除
register_hivepress_defaults()(193 行) → 搬到 HP AddOn - 把 core 內所有 HP/WC/LP 整合 class 引用加
class_exists守門 - PHP lint:111 files PASS
- Live test:
wp tmdo doctor全 PASS、wp wpdo(alias) 通
Phase 1 DoD:✅ 全達標(除舊 unit/integration test 套件需後續 phase 1 follow-up)
Phase 2 ✅ — Hub + Spoke AddOn v0.1.0 (2026-05-15)
Hub AddOn (2meet-data-optimizer-hub-addon)
TMDO_Hub_Bootstrap主啟動類別TMDO_Hub_Vendor_Field— 註冊_2meet_global_vendor_id(hp_vendor / cold zone / indexed)TMDO_Hub_Custom_Tables— 註冊 12 張2mhc_*自訂表(fallback 列表 + delegate to hub-core helper if available)- dual-emit 支援 (
tmdo_*+wpdo_*兩個 hook 路徑) - PHP lint PASS
Spoke AddOn (2meet-data-optimizer-spoke-addon)
TMDO_Spoke_Bootstrap主啟動類別TMDO_Spoke_SSO_Group— 註冊 user entityssogroup(7 欄位 → wp_wpdo_user_sso)TMDO_Spoke_Custom_Tables— 註冊2mso_sso_config/2mso_user_mappingTMDO_Spoke_CLI::sync()— 從舊_tmso_*usermeta 遷移TMDO_Spoke_CLI::force_logout()— 設置 token_expires_at = 過去- CLI 雙命名空間:
wp tmdo spoke-*+wp wpdo spoke-* - PHP lint PASS
Phase 2 Live test 結果:
- ✅ Hub: 12 hub tables 全部 OK
- ✅ Spoke: SSO group 7 fields registered, 2 tables registered
- ✅ CLI:
wp tmdo spoke-sync --dry-run跑通,spoke-force-logout --user-id=1 --dry-run跑通
Phase 3 ✅ — HP + WC + LP AddOn v0.1.0 (2026-05-15)
HivePress AddOn (2meet-data-optimizer-hivepress-addon, ~7,400 行)
- 複製 13 adapter(core / reviews / bookings / messages / memberships / requests / favorites / statistics / tags / seo / social-links / blocks / marketplace)
- 複製 7 HPCT interceptor(reviews / messages / favorites / memberships / statistics / requests / listing-meta)
- 複製 5 query interceptor(reviews / messages / memberships / requests / listing-meta)
- 複製 補助組件(bootstrap framework / detector / conflict-guard / comment-router / cron-optimizer / attribute-bridge / suitability-scorer / benchmark / rest)
- 複製 admin tab + CLI namespace
- 複製 HP transient filter / HPCT import / Listing Stats / term-comment-fields
TMDO_HP_Bootstrapouter bootstrap(避免與 inner family bootstrap class 衝突)- PHP lint:46 files PASS
WooCommerce AddOn (2meet-data-optimizer-woocommerce-addon, ~1,316 行)
- 複製 4 個 WC 整合檔
TMDO_Woocommerce_Bootstrap載入 + register- PHP lint PASS
LatePoint AddOn (2meet-data-optimizer-latepoint-addon, ~151 行)
- 複製 LatePoint interceptor
TMDO_Latepoint_Bootstrap載入 + register_hooks- PHP lint PASS
Phase 3 Live test 結果:
- ✅ Plugin 全 active
- ✅ Hot zone 20 fields registered(mostly WC product/order)
- ✅ Cold zone 3 fields
- ✅ Total 23 fields
- ✅ HP no-op when HivePress not installed(detector check)
Phase 4 ✅ — 6 個 2meet 家族 AddOn v0.1.0 (2026-05-15)
| AddOn | Source | Status |
|---|---|---|
| infocards | class-tmdo-infocards.php | ✅ |
| bookings | class-tmdo-bookings.php | ✅ |
| quotation | class-tmdo-quotation.php | ✅ |
| mobile-bridge | class-tmdo-mobile-bridge.php | ✅ |
| collab | class-tmdo-collab.php | ✅ |
| playlist | class-tmdo-playlist.php | ✅ |
每個 AddOn 都有:
TMDO_{Module}_Bootstrap啟動類別- 核心整合 class(從 wp-data-optimizer 搬入)
- partner detection (early return if target plugin not installed)
register()掛wpdo_register_fields/wpdo_register_custom_tables
Phase 4 Live test 結果:
- ✅ 6 AddOn 全 active
- ✅ Target plugin 未安裝時正確 no-op (designed behavior)
- ✅ 0 fatal、0 lint error
整體驗收(2026-05-15 末)
| 指標 | 結果 |
|---|---|
| 12 plugin active | ✅ |
| PHP lint 全 files | ✅ 203 files PASS |
wp tmdo CLI |
✅ 18 個 subcommand 全 listed |
wp wpdo alias CLI |
✅ 通 |
wp tmdo doctor |
✅ system tables 全綠 + 14 partner tables 註冊 |
wp tmdo status |
✅ 23 fields registered |
| SSO group 7 欄位 | ✅ 全 7 欄位(含 hub_global_user_id searchable) |
| Hub-addon 12 表 | ✅ 全 12 表存在 + doctor PASS |
| Spoke-addon 2 表 | ✅ 註冊 OK(DB 表 missing 是 spoke-sso 從未啟用之故) |
| WC 20 表 | ✅ 註冊 OK(DB 表 missing 是 WC 未安裝) |
| 6 family AddOn no-op | ✅ target 未安裝時正確 early return |
Lessons learned
Phase 1
- rsync 的
--exclude對tests/與tools/top-level 不生效(因為 source 路徑沒這個前綴),需後續 rm -rf 清理 - sed 全檔大寫
WPDO_→TMDO_不影響 hook/table/option 小寫前綴wpdo_,確保資料相容 - 主檔的 require chain 無法以 sed 自動產出(需手動寫,因為 require 路徑與檔名變動)
- TMDO_Core::run() 內有 8 處對「整合層 class」的硬引用,需逐個加
class_exists守門 class_alias()對 trait 與 interface 不適用(需 wrapping wrapper,留 Phase 1 follow-up)- WP 6.5+
Requires Plugins:強制檢查 Plugin Name 而非 slug;hub-core / spoke-sso 仍寫死Requires Plugins: wp-data-optimizer故無法直接啟用 → Phase 5 計畫請求 hub-core / spoke-sso 端更新或加or 2meet-data-optimizer邏輯
Phase 2
- inner Hub class
TMDO_Hub_Bootstrap需與 outer AddOn bootstrap 區分名稱(衝突避免) TMDO_Entity_Registry::register_group()是公開 API;其他 read methods (get_group_fieldsnotget_fields) 命名不直觀
Phase 3
- HP family 內部已有
TMDO_HivePress_Bootstrapclass(v3.0.0 family bootstrap),故 outer AddOn bootstrap 改名TMDO_HP_Bootstrap避免衝突
Phase 4
- 所有 family integration class 皆有 partner detection (e.g.
class_exists('TMEETIC_Plugin')) → AddOn 無需自己重複偵測
Phase 5 follow-up 執行狀態(2026-05-15)
| # | 項目 | 狀態 |
|---|---|---|
| 1 | Tests 套件搬遷:tests/unit/ 與 tests/integration/ 重命名 + path 修正 |
✅ 完成 |
| 2 | PHPCS 套件:補 phpcs.xml.dist + WordPress coding standards | ⬜ 待執行 |
| 3 | PHPUnit bootstrap:完整重建 unit/integration test 環境 | ✅ 完成 |
| 4 | DB version migration:TMDO_DB_VERSION 對齊 SCHEMA_VERSION = '2.0.0' |
✅ 完成 |
| 5 | Requires Plugins: 2meet-data-optimizer — 12 個 AddOn + brandcards header 全部更新 |
✅ 完成 |
| 6 | Trait/interface alias wrappers:Trait_TMDO_Anti_EAV_Aware 等 |
✅ 完成 |
| 7 | Doctor callback signature 修正 | ✅ 完成 |
| 8 | 打包驗收:scripts/package-plugin.sh 12 次 10 終檢 PASS |
⬜ 待執行 |
#1 + #3 完成摘要(2026-05-15)
Unit tests:373/373 GREEN(771 assertions)
phpunit.xml已建立,bootstraptests/bootstrap.php完整重建- 32 個 unit test 檔從
wp-data-optimizer搬遷,全部class-wpdo-→class-tmdo-修正 - bootstrap 新增:minimal filter registry(
$GLOBALS['_wp_filter_callbacks'])、全域 FSM bypass filter、TMDO_Listing_Statsstub、esc_sql用addslashes() - 跳過 HP/WC/LP 專屬 test(HivePress/*、WooCommerceIntegrationTest、ListingStatsTest)
Integration tests:398/398 GREEN(1139 assertions)
phpunit-integration.xml已建立,bootstraptests/integration/bootstrap.php完整重建- 35 個 integration test 檔搬遷(跳過 HivepressIntegrationTest × 3、WCTermCountFilterTest、ListingMetaInterceptorTest、TermCommentBackfillTest)
- bootstrap 新增:
wp_upload_dir()、wp_mkdir_p()、TMDO_Listing_Statsstub - 移除
WarmArchiveIntegrationTest的 listing_stats 2 個方法(需真實 HP AddOn) - 移除
RestApiIntegrationTest的 post_view increment + rate-limit 2 個方法(同上)
Backport wp-data-optimizer v3.0.1–v3.4.6(2026-07-31 起)
完整計畫:~/.claude/plans/a-data-www-studio-wp-local-dev-wp-conten-imperative-wind.md
背景:B 分叉自 A v3.0.0(2026-05-15 11:40),A 其後又走了 92 個 commit 到 v3.4.6,無一回流。目標是全量對齊後讓 wp-data-optimizer 退休。
| 階段 | 內容 | 狀態 |
|---|---|---|
| 0 | 回歸網:composer dev 依賴、test bootstrap FSM guard、failOnWarning=true、12 個 repo git init |
✅ 2026-07-31(unit 379 / integration 398 全綠) |
| 1 | 安全與正確性 A1–A14(13 個 admin GET→POST、REST allowlist、DDL 白名單、Logger 3-arity fatal…) | ✅ 2026-07-31 |
| 2 | DDL 與並發 B1–B4(warm UNIQUE KEY → Zone_Cold save_patch → Zone_Warm increment) | ✅ 2026-07-31 |
| 3 | 架構回填(Zone_Router + Routing_Predicate;13 個 Migration Phase 類別) | ✅ 2026-07-31 |
| 4 | 相容層 E1–E7(雙向 hook 橋、57 個 AddOn alias、38 個 CLI 子指令、選單 slug) | ✅ 2026-07-31 |
| 5 | AddOn 同步 F1–F5(Standard_Post_Interceptor、HP detector v3.4.5、WC) | ✅ 2026-07-31 |
| 6 | 功能與診斷 PR-G(crypto 健檢、doctor_callback ABI、15 個 usermeta 欄位…) | ✅ 2026-07-31(Settings 分區 AJAX 未做,見下) |
| 7 | 全域清理與 CI(strict_types、phpcs.xml、phpstan + baseline、gitea workflows) | 🔶 strict_types / PHPCS / PHPStan / 3 個 workflow / ci-package.sh ✅;測試補齊(剩 36 檔,多為 HP/WC)、文件移植未做 |
| 退休 | 兩站台切到 B、移除 A、B 升 1.0.0 | 🔶 dev30 已切換並驗證通過;dev 未切、A 未移除、版本未升 |
dev30 實機驗證結果(2026-07-31)
環境:2meet-brandcards 1.8.3 / 2meet-hub-core 1.16.0 / 2meet-spoke-sso 1.15.0 同時啟用;HivePress / WooCommerce 未安裝,故只啟用核心 + hub-addon + spoke-addon。
| 項目 | A v3.0.0(切換前) | B v0.1.0(切換後) |
|---|---|---|
doctor |
33 個 [OK] + 15 個 WC 表 MISSING 警告 |
49 個 [OK]、All checks passed |
| 姊妹外掛自訂表 | 36 張 OK | 36 張 OK(含 brandcards 的 doctor_callback 回傳訊息) |
| 新健檢 | 無 | Backup dir blocked (HTTP 404)、Crypto key derivable 皆 OK |
逐項確認:
- alias:15 個核心類別 + trait + interface +
wpdo_run()+WPDO_VERSION全部可用 - CLI:
wp tmdo bridge-status / crypto-status / mode-audit與wp wpdo *兩條路徑都通(38 個子指令) - anti-EAV 寫入:
WPDO_API::set_entity()→wp_wpdo_user_sso.known_login_ips寫入成功(A14 生效) - audit:
wp_wpdo_audit的group_name/action/trace_id(UUIDv4)皆有值(A11/A12 生效) - REST allowlist:註冊
show_in_rest => false的欄位不出現在get_rest_visible_hot_columns()(A5/A6 生效) - doctor_callback ABI 變更:brandcards 既有 callback 在 1 參數簽章下仍正常
- 前台 HTTP 200;
_load_textdomain_just_in_timenotice 僅出現在wp plugin activate當下(啟用鉤子早於init),一般請求與前台皆無
實機才抓到的 fatal:TMDO_Logger::trace_id() 在 B 提煉時遺漏,而 Audit_Logger::write_row() 會呼叫它。A12 把 Audit_Logger 掛上後,任何一次受管 meta 寫入都會 fatal。PHPUnit 沒有覆蓋 audit 寫入路徑 → 這類「跨模組才會踩到」的缺口只有實機能發現。
尚未完成(follow-up)
- Settings 分區 AJAX 儲存(A v3.0.2):
ajax_save_settings_section()+ 7 個save_section_*()+admin/assets/wpdo-settings.js。B 目前是一次存全部的 inlineupdate_option巨塊,功能可用,屬 UX 改善。其中save_section_hp_transient/save_section_wc_term_count對應 AddOn 已移除的設定,移植時要拆掉或加class_exists守衛。 CI workflow✅ 三個檔已建,但 B 沒有 git remote,要推上 gitea 才會實際執行;推上去後還需設 repo secretTMDO_TEST_DB_PASS、varRELEASE_GITEA_URL、secretRELEASE_TOKEN,並開 main branch protection。11 個 AddOn 的 CI 仍未建。✅(委派共用scripts/ci-package.shpackage-plugin.sh,實測 10 項終檢全 PASS)補測試檔✅ 核心補HookBusIntegrationTest(14)+ 新寫AuditLoggerIntegrationTest(4);HP AddOn 建 phpunit 基建並移植 25 檔(145 tests);WC AddOn 建基建並移植 1 檔(10 tests)。11 個 AddOn 皆有 CI workflow(HP/WC 跑 lint+unit,其餘 9 個薄註冊層只跑 lint)。- 仍缺:
TermCommentBackfillTest(require HP AddOn 的 term-comment-fields,可移入 HP AddOn 套件)、ListingStatsTest(同上)、HP/WC 的 integration 測試(HivepressIntegrationTest×3、WCTermCountFilterTest、ListingMetaInterceptorTest)——這些需要 AddOn 端的 integration bootstrap。
- 仍缺:
全家族測試現況(2026-07-31)
| 套件 | 結果 |
|---|---|
| 核心 unit | 451 tests / 889 assertions |
| 核心 integration | 416 tests / 1165 assertions |
| hivepress-addon unit | 145 tests / 357 assertions |
| woocommerce-addon unit | 10 tests / 33 assertions |
AddOn 測試 bootstrap 直接 require 核心 plugin 的 tests/bootstrap.php(避免複製 ~700 行 WP stub),因此 AddOn 的 CI job 必須同時 checkout 核心 plugin,workflow 已如此設定。
5. 文件移植:readme.txt、CONTEXT.md、docs/(ENTITY_ADAPTER_COOKBOOK、INTEGRATION_PATTERN_DECISION、2 篇 ADR)。
6. 實機驗證與退休切換:兩站台目前仍跑 A(dev = v3.4.6、dev30 = v3.0.0),B 家族 12 個外掛全 inactive,尚未做過 wp tmdo doctor 實機驗證。
ABI / 行為變更(升級須知)
doctor_callback由 3 參數改為 1 參數(表名)——AddOn 若註冊過該 callback 需同步。wpdo_capture_before_value預設true→false,每次受管寫入省一次 DB read;需要value_before的消費者(audit log)要add_filter( 'wpdo_capture_before_value', '__return_true' )。wpdo_allow_mass_column_clear現為 opt-in:delete_all=true的整欄清空預設被拒。- 選單 slug 由
2meet-data-optimizer改回wp-data-optimizer。
Lessons learned(backport)
- 階段 0 的初始 git 快照已包含階段 0 的修復(composer.json / 兩個 bootstrap / phpunit.xml / HealthCronTest),不是純粹的 pre-change 現況。要看純現況請比對 A 或
dist/內的 v0.1.0 ZIP。 composer update後 autoload 出現WPDO_Entity_Adapter_Interface三重宣告警告(includes/adapters/interface-entity-adapter.php、back-compat/interface-wpdo-entity-adapter-alias.php、back-compat/trait-wpdo-anti-eav-aware-alias.php)→ 階段 4 E2 要刪掉重複的那一份。TMDO_FSM_GUARD_DISABLED兩個 test bootstrap 原本都沒 define,但class-tmdo-feature-flags.php:128會檢查它 → 強制 FSM 轉換的測試會被 guard 擋掉(A 在 v3.4.6 踩過同一個坑)。- integration 測試需要
TMDO_TEST_DB_PASS(或WPDO_TEST_DB_PASS)環境變數,DB 為本機wp_wpdo_test。 - 跑完
scripts/ci-package.sh或package-plugin.sh後要重跑composer install:打包流程內含composer install --no-dev,會把vendor/bin/{phpunit,phpcs,phpstan}移掉,之後任何測試指令都會 "No such file or directory"。 - A 不是照抄對象,有兩處自身缺陷不可照搬:
A/includes/engine/class-wpdo-hook-bus.php:511,522傳 3 個 string 給Logger::warning( string $event, array $context )→ A 有strict_types,mass-clear 路徑必炸。B 用正確簽章。A/admin/class-wpdo-dashboard-widget.php:191的wpdo_postmeta_cleanup仍是wp_nonce_urlGET 連結,但其 handler 已只收 POST → 該按鈕在 A 是壞的。B 改成 form。
- B 有 7 處
Logger::error( 'event', array(...) )兩參數呼叫(4 個 stress tester、auto-promoter、conflict-detector、hook-bus),全部是 array→string 的 TypeError。用 token 掃描器(scan_logger.php)找出來的,肉眼與 grep 都容易漏。 Zone_Warm::set()改 upsert 後,測試表也要有UNIQUE KEY ui_post_meta,否則 integration 會出現「set 沒覆蓋舊值」的假失敗。- B 的 unit bootstrap 會載入
Member_Fields/Post_Fields,A 的不會。這使 Entity_Registry 在測試啟動時就有註冊 group,從 A 移植過來、假設「registry 為空」的測試(MigrationPhaseRemainingTest)會真的走進dbDelta而爆掉。修法是在該測試 setUp 以 reflection 清空 registry 並移除wpdo_register_entity_fieldslistener(phase 內部會再 fire 一次)。 - 快取類重構必定連帶測試隔離工作:
Routing_Predicate::flush_cache()(SyncBridgeEntityGuardTest)與Schema_Manager::flush_table_exists_cache()(PostMigrationTest / PostEntityLifecycleTest)兩處都是 A 事後才補的,移植時要一起帶,否則出現「表被 drop 但快取說還在」的假錯誤。 - B 自身的 slug 不一致:
MENU_SLUG是2meet-data-optimizer,但 help-tabs / setup-wizard / conflict-monitor / 3 個 template 共 10+ 處硬編碼page=wp-data-optimizer→ 這些連結原本全部 404。已統一回wp-data-optimizer(與 wpdo_ 表/option/cron/hook/CLI 命名空間一致)。 - 雙向 hook 橋會暴露 test bootstrap 的 stub 缺口:單向時
do_action_ref_array()從未被走到,改雙向後兩個 bootstrap 都要補這個 stub。 - AddOn 的 alias 必須各自做:核心 back-compat 在
plugins_loaded:4執行,AddOn 在:6才載入類別,核心的 alias 表涵蓋不到它們(57 個整合層類別先前完全沒有WPDO_名稱)。 - PHP 無法
class_alias()介面。WPDO_Migration_Phase_Interface沒有雙向 alias 的乾淨解法(單向extendswrapper 無法讓instanceof成立),該契約是核心內部擴充點,測試改用TMDO_正式名稱即可。
Git tag plan
v0.1.0— 本 release(Phase 0-4 完成)v0.1.1— Phase 5 follow-up(tests / PHPCS / packaging)v0.2.0— WPDO_ deprecation notice + wpdo → tmdo migration CLI