chore: initial snapshot of 2meet-data-optimizer-hub-addon v0.1.0

Baseline before backporting wp-data-optimizer v3.0.1-v3.4.6.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TbG1keQQ7XBa7qMQY16KCY
This commit is contained in:
2026-07-31 05:06:36 +08:00
commit 7f788cb4dc
15 changed files with 2711 additions and 0 deletions
+16
View File
@@ -0,0 +1,16 @@
vendor/
node_modules/
.phpunit.result.cache
.phpcs-cache
*.log
*.bak
*.swp
.DS_Store
Thumbs.db
.idea/
.vscode/
.full-review/
.gstack/
.playwright-mcp/
.claude/
dist/
+37
View File
@@ -0,0 +1,37 @@
<?php
/**
* Plugin Name: 2meet Data Optimizer — Hub AddOn
* Plugin URI: https://2meet.io/2meet-data-optimizer/hub
* Description: Hub-core 整合:postmeta _2meet_global_vendor_id (hp_vendor / cold zone) + 12 hub 自訂表註冊到 TMDO Custom Table Registry
* Version: 0.1.0
* Requires at least: 6.0
* Tested up to: 6.9.4
* Requires PHP: 8.1
* Requires Plugins: 2meet-data-optimizer, 2meet-hub-core
* Author: 2meet
* Author URI: https://2meet.io
* License: GPL-2.0-or-later
* License URI: https://www.gnu.org/licenses/gpl-2.0.html
* Text Domain: tmdo-hub
* Domain Path: /languages
*
* @package TMDO_HUB
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
define( 'TMDO_HUB_VERSION', '0.1.0' );
define( 'TMDO_HUB_PATH', plugin_dir_path( __FILE__ ) );
define( 'TMDO_HUB_URL', plugin_dir_url( __FILE__ ) );
define( 'TMDO_HUB_FILE', __FILE__ );
require_once TMDO_HUB_PATH . 'includes/class-tmdo-hub-bootstrap.php';
/**
* Phase 2 任務:完成本 AddOn 的 includes/ 實作。
*
* @see ~/.claude/plans/wp-data-optimizer-2meet-data-optimizer-zesty-liskov.md
*/
add_action( 'plugins_loaded', array( 'TMDO_Hub_Bootstrap', 'init' ), 6 );
+22
View File
@@ -0,0 +1,22 @@
# Changelog
All notable changes to this AddOn will be documented here.
Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
Versioning follows [Semantic Versioning](https://semver.org/).
---
## [Unreleased]
- Phase 2 implementation in progress.
---
## [0.1.0] — TBD
### Added (initial release, scaffold)
- Plugin scaffold from `wp-data-optimizer v2.16.0` extraction plan.
- Plugin Header + bootstrap stub + 7 MD + composer.json.
- Requires Plugins: `2meet-data-optimizer`, `2meet-hub-core`.
+74
View File
@@ -0,0 +1,74 @@
# CLAUDE.md — 2meet Data Optimizer Hub AddOn
> 父外掛:`../2meet-data-optimizer/CLAUDE.md`
> 父環境:`/var/www/Studio/wp-local-dev30/CLAUDE.md`
> 全域:`~/.claude/CLAUDE.md`(含 Karpathy Guidelines
---
## Reset recovery
1. 讀本檔
2. 讀 [PLAN.md](PLAN.md) 看 Phase 2 進度
3. 接續下一個未完成步驟
---
## Plugin 概述
**2meet-data-optimizer-hub-addon** 是 2meet-data-optimizer 的 Hub 整合 AddOn。
- **目標外掛**: `2meet-hub-core`
- **Phase**: 2
- **預估行數**: ~280
- **Slug 短碼**: `hub`
簡述:Hub-core 整合:postmeta _2meet_global_vendor_id + 12 hub 自訂表註冊
完整拆分計畫見 `~/.claude/plans/wp-data-optimizer-2meet-data-optimizer-zesty-liskov.md`
---
## 邊界
- ✅ 本 AddOn 觸碰:hub 相關 schema 註冊(postmeta zone fields / custom tables / entity groups+ 可選 admin / CLI
- ❌ 本 AddOn **不**觸碰:2meet-data-optimizer 核心、其他 AddOn、目標外掛 runtime 邏輯
- ❌ 本 AddOn **不**繞過:Hook Bus / TMDO_API(必須走公開合約)
---
## 命名前綴
- 類別:`TMDO_Hub_*`
- 函式:`tmdo_hub_*`
- 常數:`TMDO_HUB_VERSION` / `TMDO_HUB_PATH` / `TMDO_HUB_URL` / `TMDO_HUB_FILE`
- Text-domain`tmdo-hub`
---
## 公開合約消費(從核心)
```php
// 安全消費 API(必加 class_exists guard
if ( class_exists( 'TMDO_API' ) ) {
TMDO_API::set_entity( 'user', $id, 'key', $value );
}
// Schema 註冊
add_action( 'tmdo_register_entity_fields', function ( $registry_class ) {
$registry_class::register_group( '...', '...', [ ... ] );
} );
add_action( 'tmdo_register_custom_tables', function ( $registry ) {
$registry->register( 'hub-addon', [ ... ] );
} );
```
---
## Phase 進度
```
Phase 0 ✅ 骨架建立 (2026-05-15)
Phase 2 ⬜ Implementation v0.1.0
```
+43
View File
@@ -0,0 +1,43 @@
# 部署流程
## Prerequisites
1. `2meet-data-optimizer` 核心 ≥ 0.1.0 已安裝並啟用
2. `2meet-hub-core` 已安裝並啟用
> 本 AddOn 透過 WordPress `Requires Plugins:` 強制相依,先決條件未滿足時無法啟用。
---
## Steps
```bash
# 上傳 + 啟用
wp plugin install /path/to/2meet-data-optimizer-hub-addon-v0.1.0.zip --activate
# 驗證
wp tmdo doctor --provider=hub-addon
wp tmdo custom-tables --provider=hub-addon
```
---
## Rollback
```bash
wp plugin deactivate 2meet-data-optimizer-hub-addon
# 目標外掛 (2meet-hub-core) 仍可正常運作,
# 讀寫 fall back 到 native meta(失去 zone 加速但功能不受影響)
```
---
## 整體部署順序建議
依 Phase 順序:
1. `2meet-data-optimizer` 核心
2. Phase 2: `2meet-data-optimizer-hub-addon``2meet-data-optimizer-spoke-addon`
3. Phase 3: HivePress / WooCommerce / LatePoint AddOn
4. Phase 4: 6 個 2meet 家族 AddOn
詳見核心外掛 [DEPLOY.md](../2meet-data-optimizer/DEPLOY.md)。
+44
View File
@@ -0,0 +1,44 @@
# DESIGN — 2meet Data Optimizer Hub AddOn
> 父外掛架構決策見 [`../2meet-data-optimizer/DESIGN.md`](../2meet-data-optimizer/DESIGN.md)
---
## 角色定位
本 AddOn 是 `2meet-data-optimizer` 的整合層,負責將 `2meet-hub-core` 的 EAV 模式(postmeta / 自訂表)橋接到核心反 EAV 引擎。
- **不**修改 `2meet-hub-core` 本身
- **不**繞過 `2meet-data-optimizer` 核心
- 只透過公開合約(`TMDO_API``tmdo_register_*` hook)參與
---
## 啟動順序
```
plugins_loaded:4 2meet-data-optimizer (core) 啟動
plugins_loaded:5-6 本 AddOn bootstrap → 註冊 hook callback
plugins_loaded:6+ 2meet-hub-core 本體啟動
init:0 核心 fire tmdo_register_* → 本 AddOn 的 callback 執行
```
詳見 plan 文件第 3 章「載入順序」。
---
## 為什麼是獨立 AddOn 而非塞進核心
- 核心 `2meet-data-optimizer` 對外承諾「零依存任何業務外掛」
- 整合層發版節奏應跟隨 `2meet-hub-core` 而非核心
- 站台不用 `2meet-hub-core` 時不需被迫載入這段程式碼
---
## 邊界檢查清單
- [ ] 不直接 `SELECT FROM wp_*meta`
- [ ] 不繞過 Hook Bus
- [ ] 所有 SQL 走 `$wpdb->prepare()`
- [ ] DB 表名走 `TMDO_DB::table()`
- [ ] 對外只 expose `TMDO_Hub_*` 命名空間
+43
View File
@@ -0,0 +1,43 @@
# PLAN — 2meet Data Optimizer Hub AddOn
> 完整四階段拆分計畫見 `~/.claude/plans/wp-data-optimizer-2meet-data-optimizer-zesty-liskov.md` (本 AddOn 屬 **Phase 2**)
---
## Current state
- **Version**: 0.1.0 (in development, scaffold complete 2026-05-15)
- **Phase**: Phase 0 → Phase 2 pending
- **Source**: 從 `wp-data-optimizer v2.16.0` 提煉
- **預估行數**: ~280 行
- **目標外掛**: `2meet-hub-core`
---
## Phase 0 ✅ — 骨架建立 (2026-05-15)
- [x] 目錄結構
- [x] Plugin Header
- [x] Bootstrap stub
- [x] 7 件 MD
- [x] composer.json / .gitignore / uninstall.php
---
## Phase 2 ⬜ — Implementation v0.1.0
詳細任務見上層 plan 第 5 章。簡述:
- [ ] 從 wp-data-optimizer 對應檔案搬入 includes/
- [ ] WPDO_ → TMDO_Hub_ 重命名
- [ ] 移除對 wp-data-optimizer 內部 class 的依存(改走 TMDO_API 公開合約)
- [ ] 完善 bootstrap:實作 init() 載入順序
- [ ] 補完 7 件 MD 的細節
- [ ]`scripts/package-plugin.sh 2meet-data-optimizer-hub-addon` 通過 10 終檢
- [ ] dev30 e2e
---
## Lessons learned
- (Phase 2 起記錄)
+60
View File
@@ -0,0 +1,60 @@
# 2meet Data Optimizer — Hub AddOn
> 為 **2meet-hub-core**OAuth IdP & 身份中樞)提供 schema 註冊與健康檢查整合。
---
## What it does
把 hub-core 既有對 \`wp-data-optimizer\` 的依存抽出來,集中在這個 AddOn:
| 項目 | 內容 |
|---|---|
| Postmeta 欄位 | `_2meet_global_vendor_id` (hp_vendor / cold zone / indexed) |
| Custom tables | 12 張 hub 自訂表(`2mhc_oauth_clients` / `auth_codes` / `access_tokens` / `refresh_tokens` / `slo_state` / `user_identities` / `vendor_sites` / `aggregated_services` / `brand_pages` / `audit_log` / `sync_inbox` / `rate_limits`)→ 註冊到 TMDO Custom Table Registry,享有 `wp tmdo doctor` 健診 + schema drift 偵測 |
| Crypto bridge | TMDO_Crypto wrapper,與 hub-core OAuth refresh_token 加密互通 |
---
## Requirements
- WordPress ≥ 6.0
- PHP ≥ 8.1
- 2meet-data-optimizer ≥ 0.1.0
- 2meet-hub-core ≥ 1.16.0
---
## Installation
```bash
wp plugin install /path/to/2meet-data-optimizer-hub-addon-v0.1.0.zip --activate
# 驗證
wp tmdo custom-tables --provider=hub-addon
wp tmdo doctor --provider=hub-addon
```
WordPress 強制相依:未先啟用 `2meet-data-optimizer` + `2meet-hub-core` 無法啟用此 AddOn。
---
## 為什麼是 AddOn 而非 hub-core 內建
- 核心 `2meet-data-optimizer` 對外承諾「零依存」,hub schema 不應污染核心
- hub-core 自身不應直接呼叫 `WPDO_Schema_Registry`(介面耦合過深)
- AddOn 居中橋接,hub-core 升版只需動 hub-core,核心不受影響
---
## Phase
Phase 2 — 與 [Spoke AddOn](../2meet-data-optimizer-spoke-addon/) 同期 ship。
詳見 [PLAN.md](PLAN.md) 與 [DESIGN.md](DESIGN.md)。
---
## License
GPL-2.0-or-later
+36
View File
@@ -0,0 +1,36 @@
# Security Policy
## Supported versions
| Version | Supported |
|---|:-:|
| 0.1.x | ✅ |
---
## Reporting a vulnerability
請參考核心外掛 [SECURITY.md](../2meet-data-optimizer/SECURITY.md)。
簡述:
- Email: security@2meet.io
- 請勿在 public GitHub issue 揭露
- 24h 內初步回應、7 天內提供修補時程
---
## 安全設計
本 AddOn 完全遵守 2meet-data-optimizer 核心安全設計:
- SQL prepared statements
- Capability check (`manage_options`)
- Nonce 驗證
- Output escaping
- 反序列化走 `TMDO_Safe_Unserialize`
---
## 已知 Risk
- (本版本暫無已知安全 riskPhase 2 ship 時補)
+25
View File
@@ -0,0 +1,25 @@
{
"name": "2meet/2meet-data-optimizer-hub-addon",
"description": "Hub-core 整合:postmeta _2meet_global_vendor_id + 12 hub 自訂表註冊",
"type": "wordpress-plugin",
"license": "GPL-2.0-or-later",
"keywords": ["wordpress", "2meet-data-optimizer", "addon", "hub"],
"require": {
"php": ">=8.1"
},
"require-dev": {
"phpunit/phpunit": "^10.5",
"wp-coding-standards/wpcs": "^3.0"
},
"scripts": {
"phpcs": "phpcs --standard=WordPress includes/ 2meet-data-optimizer-hub-addon.php"
},
"config": {
"allow-plugins": {
"dealerdirect/phpcodesniffer-composer-installer": true
},
"optimize-autoloader": true,
"preferred-install": "dist",
"sort-packages": true
}
}
Generated
+2106
View File
File diff suppressed because it is too large Load Diff
+48
View File
@@ -0,0 +1,48 @@
<?php
/**
* Bootstrap for 2meet Data Optimizer Hub AddOn.
*
* 負責 hub-core 對 2meet-data-optimizer 反 EAV 引擎的 schema 整合:
* - 註冊 `_2meet_global_vendor_id` postmeta 到 cold zone (hp_vendor)
* - 將 hub-core 12 張自訂表註冊到 TMDO Custom Table Registry(享有 doctor + drift 偵測)
*
* @package TMDO_HUB
* @since 0.1.0
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
require_once TMDO_HUB_PATH . 'includes/class-tmdo-hub-vendor-field.php';
require_once TMDO_HUB_PATH . 'includes/class-tmdo-hub-custom-tables.php';
final class TMDO_Hub_Bootstrap {
public static function init(): void {
if ( ! class_exists( 'TMDO_API' ) && ! class_exists( 'WPDO_API' ) ) {
add_action( 'admin_notices', array( __CLASS__, 'missing_core_notice' ) );
return;
}
load_plugin_textdomain(
'tmdo-hub',
false,
dirname( plugin_basename( TMDO_HUB_FILE ) ) . '/languages'
);
// 接 tmdo_* 與 wpdo_* 雙向相容(核心 dual-fire 已配對,但這裡兩邊掛 callback 不會重複觸發
// — class 內部以 static $registered guard 確保 idempotent)。
add_action( 'tmdo_register_fields', array( 'TMDO_Hub_Vendor_Field', 'register' ), 10, 1 );
add_action( 'wpdo_register_fields', array( 'TMDO_Hub_Vendor_Field', 'register' ), 10, 1 );
add_action( 'tmdo_register_custom_tables', array( 'TMDO_Hub_Custom_Tables', 'register' ), 10, 1 );
add_action( 'wpdo_register_custom_tables', array( 'TMDO_Hub_Custom_Tables', 'register' ), 10, 1 );
}
public static function missing_core_notice(): void {
echo '<div class="notice notice-error"><p>';
echo esc_html__( '2meet Data Optimizer Hub AddOn 需要 2meet-data-optimizer 核心外掛,請先安裝並啟用。', 'tmdo-hub' );
echo '</p></div>';
}
}
+100
View File
@@ -0,0 +1,100 @@
<?php
/**
* Register 12 hub-core custom tables to TMDO Custom Table Registry.
*
* 從 2meet-hub-core/includes/class-tmhc-plugin.php:222-245 抽出。
* 表 schema 定義仍由 hub-core 擁有(透過 tmhc_get_table_suffixes() 等 helper 取得)。
*
* @package TMDO_HUB
* @since 0.1.0
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
final class TMDO_Hub_Custom_Tables {
private static bool $registered = false;
/**
* Hub 12 表清單(fallback 當 tmhc_get_table_suffixes 不可用時)。
*/
private const FALLBACK_SUFFIXES = array(
'2mhc_oauth_clients',
'2mhc_oauth_auth_codes',
'2mhc_oauth_access_tokens',
'2mhc_oauth_refresh_tokens',
'2mhc_oauth_slo_state',
'2mhc_user_identities',
'2mhc_vendor_sites',
'2mhc_aggregated_services',
'2mhc_brand_pages',
'2mhc_audit_log',
'2mhc_sync_inbox',
'2mhc_rate_limits',
);
/**
* Register tables to TMDO Custom Table Registry.
*
* @param object $registry TMDO_Custom_Table_Registry / WPDO_Custom_Table_Registry instance.
*/
public static function register( $registry ): void {
if ( self::$registered ) {
return;
}
if ( ! is_object( $registry ) || ! method_exists( $registry, 'register' ) ) {
return;
}
$suffixes = self::get_suffixes();
$expected_columns = self::get_expected_columns_safe();
$expected_indexes = self::get_expected_indexes_safe();
foreach ( $suffixes as $suffix ) {
$registry->register(
'2meet-data-optimizer-hub-addon',
array(
'table_name' => $suffix,
'primary_key' => 'id',
'expected_columns' => $expected_columns[ $suffix ] ?? array(),
'indexes' => $expected_indexes[ $suffix ] ?? array(),
'description' => '2meet Hub Core 自訂表:' . $suffix,
)
);
}
self::$registered = true;
}
private static function get_suffixes(): array {
if ( function_exists( 'tmhc_get_table_suffixes' ) ) {
$out = tmhc_get_table_suffixes();
if ( is_array( $out ) && ! empty( $out ) ) {
return $out;
}
}
return self::FALLBACK_SUFFIXES;
}
private static function get_expected_columns_safe(): array {
if ( class_exists( 'TMHC_Plugin' ) && method_exists( 'TMHC_Plugin', 'get_expected_columns' ) ) {
$reflection = new ReflectionMethod( 'TMHC_Plugin', 'get_expected_columns' );
if ( $reflection->isStatic() && $reflection->isPublic() ) {
return TMHC_Plugin::get_expected_columns();
}
}
return array();
}
private static function get_expected_indexes_safe(): array {
if ( class_exists( 'TMHC_Plugin' ) && method_exists( 'TMHC_Plugin', 'get_expected_indexes' ) ) {
$reflection = new ReflectionMethod( 'TMHC_Plugin', 'get_expected_indexes' );
if ( $reflection->isStatic() && $reflection->isPublic() ) {
return TMHC_Plugin::get_expected_indexes();
}
}
return array();
}
}
+43
View File
@@ -0,0 +1,43 @@
<?php
/**
* Hub vendor postmeta field registration.
*
* 從 2meet-hub-core/includes/class-tmhc-plugin.php:204-213 抽出。
*
* @package TMDO_HUB
* @since 0.1.0
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
final class TMDO_Hub_Vendor_Field {
private static bool $registered = false;
/**
* Register `_2meet_global_vendor_id` to cold zone for hp_vendor post type.
*
* @param object $registry TMDO_Schema_Registry / WPDO_Schema_Registry instance.
*/
public static function register( $registry ): void {
if ( self::$registered ) {
return;
}
if ( ! is_object( $registry ) || ! method_exists( $registry, 'register' ) ) {
return;
}
$registry->register(
'2meet-data-optimizer-hub-addon',
array(
'meta_key' => '_2meet_global_vendor_id',
'post_type' => 'hp_vendor',
'zone' => 'cold',
'data_type' => 'bigint',
'indexed' => true,
)
);
self::$registered = true;
}
}
+14
View File
@@ -0,0 +1,14 @@
<?php
/**
* Uninstall handler for 2meet Data Optimizer Hub AddOn.
*
* 僅清理本 AddOn 自有 schema(核心 wp_wpdo_* 系統表保留給 core)。
*
* @package TMDO_HUB
*/
if ( ! defined( 'WP_UNINSTALL_PLUGIN' ) ) {
exit;
}
// Phase 2 完整實作。Phase 0 stub:保留所有資料以避免誤刪。