docs(2meet-data-optimizer): 1.2.0 release notes
- Bump to 1.2.0; CHANGELOG / readme entries for PR-066–080, with the post-upgrade ops commands - ADR-004 Release 2.2 design (scope, drift check / fix / router / resync) and CONTEXT.md drift paragraph - Verify: composer test, integration, phpcs 0 - PR: PR-086
This commit is contained in:
@@ -3,7 +3,7 @@
|
|||||||
* Plugin Name: 2meet Data Optimizer
|
* Plugin Name: 2meet Data Optimizer
|
||||||
* Plugin URI: https://2meet.io/2meet-data-optimizer
|
* Plugin URI: https://2meet.io/2meet-data-optimizer
|
||||||
* Description: 通用 WordPress 反 EAV 引擎:將 postmeta / usermeta / termmeta / commentmeta 自動分流至四象限扁平表(Hot / Warm / Cold / Archive),大幅提升搜尋與篩選效能。從 wp-data-optimizer v2.16.0 提煉的純核心,整合層交給 11 個 AddOn。
|
* Description: 通用 WordPress 反 EAV 引擎:將 postmeta / usermeta / termmeta / commentmeta 自動分流至四象限扁平表(Hot / Warm / Cold / Archive),大幅提升搜尋與篩選效能。從 wp-data-optimizer v2.16.0 提煉的純核心,整合層交給 11 個 AddOn。
|
||||||
* Version: 1.1.1
|
* Version: 1.2.0
|
||||||
* Requires at least: 6.0
|
* Requires at least: 6.0
|
||||||
* Tested up to: 6.9.4
|
* Tested up to: 6.9.4
|
||||||
* Requires PHP: 8.1
|
* Requires PHP: 8.1
|
||||||
@@ -26,7 +26,7 @@ if ( ! defined( 'ABSPATH' ) ) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ── Constants ──────────────────────────────────────────────────────────────
|
// ── Constants ──────────────────────────────────────────────────────────────
|
||||||
define( 'TMDO_VERSION', '1.1.1' );
|
define( 'TMDO_VERSION', '1.2.0' );
|
||||||
define( 'TMDO_DB_VERSION', '2.1.0' );
|
define( 'TMDO_DB_VERSION', '2.1.0' );
|
||||||
define( 'TMDO_PATH', plugin_dir_path( __FILE__ ) );
|
define( 'TMDO_PATH', plugin_dir_path( __FILE__ ) );
|
||||||
define( 'TMDO_URL', plugin_dir_url( __FILE__ ) );
|
define( 'TMDO_URL', plugin_dir_url( __FILE__ ) );
|
||||||
|
|||||||
@@ -7,6 +7,80 @@ Versioning follows [Semantic Versioning](https://semver.org/).
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## [1.2.0] — 2026-09-27 — 漂移偵測、範圍收斂、CLI 與診斷(hardening 2.2)
|
||||||
|
|
||||||
|
**性質**:功能 + 資料正確性修正。無 schema 變更。延續 ADR-004 的搜尋索引模式;搭配
|
||||||
|
HivePress AddOn 0.3.0、WooCommerce AddOn 0.2.0。
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- **`wp tmdo drift-check <entity> [--group] [--sample=<n>] [--format]`**(`TMDO_Drift_Check`):
|
||||||
|
逐 key 比對扁平表與原生 meta 的值(第一筆原生 row → 安全 unserialize →
|
||||||
|
`Type_Caster::to_db`),回報 miss / diff / extra。序列化 vs JSON、`50` vs `50.000000`
|
||||||
|
不算漂移;超過 255 字元存 NULL 的 text 不算 miss。結果寫入 `wpdo_drift_status`。(PR-070)
|
||||||
|
- **`drift-check --fix`**:刪除已刪實體與非本 group post type 的扁平列,其餘漂移列經
|
||||||
|
`TMDO_Entity_Migration_Engine::migrate_entity()` 從原生重建,清除列快取後再檢查一次。
|
||||||
|
不寫原生;aeav_only(扁平才是真實資料)一律拒絕。(PR-071、PR-073b)
|
||||||
|
- **每日抽樣**:`wpdo_daily_health_check` 對 dual_write 以上、非 aeav_only 的 entity 每個
|
||||||
|
group 抽 500 筆,結果取代既有紀錄。(PR-073)
|
||||||
|
- **Hook Bus 關閉期間的寫入補回**:entity 從 disabled 進入 dual_write / shadow_read,或
|
||||||
|
Hook Bus flag 由關轉開時,60 秒後以單次 WP-Cron `tmdo_drift_resync` 執行全量
|
||||||
|
`drift-check --fix`(不做 `post_modified_gmt` 增量:WooCommerce 直接 SQL 改庫存不會更新
|
||||||
|
post_modified)。停用 / 解除安裝時清除排程。(PR-074)
|
||||||
|
- **`wp tmdo bridge-mode <entity> <mode>`**:經 `TMDO_Mode_Manager::set()`,受
|
||||||
|
Promotion Guard 約束;被拒時 exit 1、模式不變。(PR-069)
|
||||||
|
- **`wp tmdo member-backfill --all`**:回填所有已註冊的 user group。(PR-068)
|
||||||
|
- **`wp tmdo cleanup-hp-transients --options [--dry-run|--confirm] [--batch=<n>]`**:
|
||||||
|
刪除 HivePress AddOn 0.3.0 之前寫進 wp_options 的 `_transient_wpdo_hp_pm_*`(含 timeout),
|
||||||
|
分批刪除(預設 5000),AddOn 未啟用也可執行。dev36 有 2,314,750 列。(PR-080)
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- **Post query router 避開漂移中的 group**:上次 drift-check 有 miss / diff / extra 的
|
||||||
|
group 不路由,整個查詢維持原生(全有或全無);從未檢查的 group 照常路由;aeav_only
|
||||||
|
不受影響。(PR-072、PR-073b)
|
||||||
|
- **純排序搜尋 flat-first**:沒有路由篩選的 HivePress `_sort` 搜尋,在該 post type 每篇都有
|
||||||
|
扁平列時改由扁平表驅動(`STRAIGHT_JOIN` + INNER JOIN);Router 在 `wp_insert_post`
|
||||||
|
替新文章建空列,覆蓋率以 anti-join 檢查並快取 15 分鐘(隨 post 模式變更失效)。
|
||||||
|
flat-first 且扁平表是唯一 JOIN 時拿掉 WordPress 為 tax query 加的 `GROUP BY posts.ID`。
|
||||||
|
dev36 `rating__desc`:原生約 3.3 s、1.1.0 約 1.5–1.9 s、現在約 0.51–0.85 s。(PR-079)
|
||||||
|
- **Auto-promoter** 的第三個條件改為 `TMDO_Drift_Check::clean_since()`:2 天內每個 group 都
|
||||||
|
檢查過(抽樣或全量)且沒有漂移;沒有紀錄就不升級。(PR-075)
|
||||||
|
- **shadow_read diff 節流**:每個 entity type + key 每小時最多記 20 列(疊加既有的
|
||||||
|
每物件 5 分鐘視窗)。(PR-075)
|
||||||
|
- **回填 group 改讀 registry**:admin「全部回填」、`post-migrate-group`、`member-backfill`、
|
||||||
|
`member-audit` 取所有已註冊 group(排除已還原的孤兒 group),不再是寫死清單;含 json
|
||||||
|
欄位的 group(attachment、nav_menu_item)逐列經 migration engine。(PR-067、PR-068)
|
||||||
|
- **不再註冊 `post/wc_product`**:WooCommerce 直接讀 product meta、以 SQL 寫庫存,扁平副本
|
||||||
|
必然漂移(ADR-004 決策 2)。既有的 `wp_wpdo_post_wc_product` 表保留,以
|
||||||
|
`wp tmdo bridge-restore-native post --group=wc_product --retire` 封存;解除安裝仍會刪除。(PR-077)
|
||||||
|
- `member-sso-sync`、`member-force-logout` 標示為 deprecated(`sso` group 已不註冊)。(PR-069)
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- Entity 回填替沒有原生 row 的 key 寫入 DDL 預設值(`session_count` / `account_flags` = 0),
|
||||||
|
每個 user 都被捏造出 0;現在寫 NULL,required NOT NULL 欄位保留預設值。(PR-066)
|
||||||
|
- `member-cutover` 在轉換被拒時 fatal(把 `WP_Error` 當陣列)。(PR-068)
|
||||||
|
- `doctor` 依 registry 檢查 entity 表(不再因從未註冊的 `sso` 表而每站失敗),並顯示
|
||||||
|
Promotion Guard 違規與 drift 狀態;`term-comment-diagnose` 依各 filter 的 `is_enabled()`
|
||||||
|
顯示狀態;`bridge-status` 只計有值的扁平列、eav_ids 限定 group 的 post type
|
||||||
|
(dev36 wp_core 15306% → 100%)。(PR-076)
|
||||||
|
- 2.1 稽核:公開 REST route 註明公開理由;admin 23 處三元 echo 依情境 `esc_attr` /
|
||||||
|
`esc_html`;migration engine 與 health cron 的例外改記 `TMDO_Logger`。(PR-078)
|
||||||
|
|
||||||
|
### Docs
|
||||||
|
|
||||||
|
- ADR-004「設計(Release 2.2)」、`CONTEXT.md` Entity Bridge 的漂移段落。(PR-086)
|
||||||
|
|
||||||
|
### 升級後
|
||||||
|
|
||||||
|
- HivePress 站:部署 AddOn 0.3.0 後執行 `wp tmdo cleanup-hp-transients --options --confirm`。
|
||||||
|
- 曾註冊 wc_product 的站:`wp tmdo bridge-restore-native post --group=wc_product --retire`。
|
||||||
|
- 已進入 dual_write 以上的站:`wp tmdo drift-check <entity>` 建立第一筆紀錄(未檢查的
|
||||||
|
group 照常路由)。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## [1.1.1] — 2026-09-26 — Security:公開 REST 不再回傳私有欄位
|
## [1.1.1] — 2026-09-26 — Security:公開 REST 不再回傳私有欄位
|
||||||
|
|
||||||
**性質**:安全修正(Critical)。1.0.x 起即存在;1.1.0 zip 已撤回(`dist/withdrawn/`)。
|
**性質**:安全修正(Critical)。1.0.x 起即存在;1.1.0 zip 已撤回(`dist/withdrawn/`)。
|
||||||
|
|||||||
@@ -158,6 +158,13 @@ semantics, LIKE as `%esc_like%`. Meta ordering (the HivePress `_sort` NOT EXISTS
|
|||||||
shape, a named clause, `meta_key` + `meta_value_num`) is routed only as the sole
|
shape, a named clause, `meta_key` + `meta_value_num`) is routed only as the sole
|
||||||
`orderby` on a column that orders like native.
|
`orderby` on a column that orders like native.
|
||||||
|
|
||||||
|
**Drift** (v1.2.0). `TMDO_Drift_Check` compares flat values with native meta per key
|
||||||
|
(miss / diff / extra) and records the outcome per group in `wpdo_drift_status`;
|
||||||
|
`--fix` rebuilds flat rows from native. The router routes no clause of a group recorded
|
||||||
|
as drifting (never checked → routes). A daily sample, and a full fix 60 s after an
|
||||||
|
entity leaves `disabled` or the Hook Bus is switched back on (`tmdo_drift_resync`), keep
|
||||||
|
the record current. None of this applies in `aeav_only`, where flat is the source of truth.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Migration Phase (Strategy pattern)
|
## Migration Phase (Strategy pattern)
|
||||||
|
|||||||
@@ -77,6 +77,26 @@
|
|||||||
|
|
||||||
HivePress AddOn 0.2.0 在 post router 啟用時不再綁定舊的 hot-zone `optimize_query` / `optimize_search`。
|
HivePress AddOn 0.2.0 在 post router 啟用時不再綁定舊的 hot-zone `optimize_query` / `optimize_search`。
|
||||||
|
|
||||||
|
## 設計(Release 2.2)
|
||||||
|
|
||||||
|
### 範圍收斂
|
||||||
|
|
||||||
|
- core 不再註冊 `post/wc_product`;WooCommerce AddOn 0.2.0 不再註冊 product / order / subscription 的 zone 欄位與 user `hot` 群組。WooCommerce 的 meta 只存在原生。既有表以 `bridge-restore-native post --group=wc_product --retire` 封存。
|
||||||
|
|
||||||
|
### 漂移偵測與修復(`TMDO_Drift_Check`)
|
||||||
|
|
||||||
|
- `wp tmdo drift-check <entity>` 以值比對扁平與原生(第一筆原生 row → 安全 unserialize → `Type_Caster::to_db`),逐 key 回報 miss / diff / extra,結果寫入 `wpdo_drift_status`。
|
||||||
|
- `--fix` 從原生重建漂移列,刪除已刪實體與非本 group post type 的列,不寫原生。
|
||||||
|
- **aeav_only 不適用**:那時扁平才是真實資料,原生本來就過期。`--fix` 拒絕、每日抽樣略過、Router 不因漂移退回原生。
|
||||||
|
- **Router**:上次檢查有漂移的 group 不路由,整個查詢維持原生;從未檢查的 group 照常路由(決策 2026-09-27:升級後不變慢)。
|
||||||
|
- **每日抽樣**:`wpdo_daily_health_check`,每 group 500 筆。
|
||||||
|
- **Hook Bus 關閉期間的寫入**:entity 從 disabled 進入 dual_write / shadow_read、或 Hook Bus flag 由關轉開時,60 秒後 `tmdo_drift_resync` 執行全量 `--fix`。不用 `post_modified_gmt` 增量,因為 WooCommerce 直接 SQL 寫 meta 不會更新它。
|
||||||
|
- **Auto-promoter** 以 `clean_since()`(2 天內乾淨的檢查)取代 shadow diff 數量;Promotion Guard 仍擋 HP / WC 站。
|
||||||
|
|
||||||
|
### 查詢
|
||||||
|
|
||||||
|
- 純排序搜尋(HivePress `_sort`、沒有路由篩選)在該 post type 每篇都有扁平列時改由扁平表驅動;Router 在 `wp_insert_post` 替新文章建空列,覆蓋率快取 15 分鐘。
|
||||||
|
|
||||||
## 後果
|
## 後果
|
||||||
|
|
||||||
**好處**
|
**好處**
|
||||||
@@ -89,7 +109,7 @@ HivePress AddOn 0.2.0 在 post router 啟用時不再綁定舊的 hot-zone `opti
|
|||||||
|
|
||||||
- **寫入開銷**:dual_write / shadow_read 每次 meta 寫入多一次原生讀取與一次扁平寫入。dev36 實測 HP listing 整條寫入鏈 +29%、WC product +127%(後者在 2.2 移除 WC 扁平化後消失)。
|
- **寫入開銷**:dual_write / shadow_read 每次 meta 寫入多一次原生讀取與一次扁平寫入。dev36 實測 HP listing 整條寫入鏈 +29%、WC product +127%(後者在 2.2 移除 WC 扁平化後消失)。
|
||||||
- **沒有讀取加速**:帶 key 的單筆讀取仍走原生(WordPress meta cache)。
|
- **沒有讀取加速**:帶 key 的單筆讀取仍走原生(WordPress meta cache)。
|
||||||
- **漂移**:繞過 meta API 的寫入(直接 SQL、Hook Bus 關閉期間的匯入)會讓扁平表過期,Router 會回傳過期的篩選結果。2.2 的 `drift-check` 與重新啟用時的增量 backfill(E01 / E02)處理;在那之前,大量匯入後要重新 backfill。
|
- **漂移**:繞過 meta API 的寫入(直接 SQL、Hook Bus 關閉期間的匯入)會讓扁平表過期,Router 會回傳過期的篩選結果。2.2 起由 `drift-check`(每日抽樣、Router 避開漂移中的 group)與重新啟用時的全量 `--fix` 處理;兩次抽樣之間的漂移仍可能短暫回傳過期結果,大量匯入後可手動執行 `drift-check <entity> --fix`。
|
||||||
- **decimal 欄位搭配 NUMERIC / DECIMAL**:原生先 CAST 成整數(`DECIMAL` 預設 (10,0)),扁平表精確比較,因此帶小數的值在區間邊界上可能不同。dev36 資料沒有這種值。
|
- **decimal 欄位搭配 NUMERIC / DECIMAL**:原生先 CAST 成整數(`DECIMAL` 預設 (10,0)),扁平表精確比較,因此帶小數的值在區間邊界上可能不同。dev36 資料沒有這種值。
|
||||||
- **text 欄位超過 255 字元**存 NULL,這類值的篩選結果會與原生不同(有 `text_overflow` 記錄)。
|
- **text 欄位超過 255 字元**存 NULL,這類值的篩選結果會與原生不同(有 `text_overflow` 記錄)。
|
||||||
- HivePress 搜尋 p50 為 321–866 ms(原生 600–1,713 ms),尚未達到 R-2.1 的 300 ms 目標(驗收:`notes/tmdo-acceptance-2.1-2026-09-26.md`)。價格篩選頁的 SQL 只剩約 75 ms、其餘為頁面渲染;純排序(如 `rating__desc`)必須 LEFT JOIN 保留沒有值的文章,無法 flat-first。
|
- HivePress 搜尋 p50 為 321–866 ms(原生 600–1,713 ms),尚未達到 R-2.1 的 300 ms 目標(驗收:`notes/tmdo-acceptance-2.1-2026-09-26.md`)。價格篩選頁的 SQL 只剩約 75 ms、其餘為頁面渲染;純排序(如 `rating__desc`)必須 LEFT JOIN 保留沒有值的文章,無法 flat-first。
|
||||||
|
|||||||
+13
-1
@@ -4,7 +4,7 @@ Tags: performance, database, postmeta, optimization, hivepress
|
|||||||
Requires at least: 6.0
|
Requires at least: 6.0
|
||||||
Tested up to: 6.9
|
Tested up to: 6.9
|
||||||
Requires PHP: 8.1
|
Requires PHP: 8.1
|
||||||
Stable tag: 1.1.1
|
Stable tag: 1.2.0
|
||||||
License: GPLv2 or later
|
License: GPLv2 or later
|
||||||
License URI: https://www.gnu.org/licenses/gpl-2.0.html
|
License URI: https://www.gnu.org/licenses/gpl-2.0.html
|
||||||
|
|
||||||
@@ -107,6 +107,18 @@ The Classifier tab analyzes your existing `wp_postmeta` data (access frequency,
|
|||||||
|
|
||||||
== Changelog ==
|
== Changelog ==
|
||||||
|
|
||||||
|
= 1.2.0 =
|
||||||
|
* `wp tmdo drift-check <entity> [--group] [--sample] [--fix]`: reports flat-vs-native drift per key (miss / diff / extra) and rebuilds drifted flat rows from native; native meta is never written, and aeav_only sites are refused
|
||||||
|
* The post query router keeps a query native while one of its groups is recorded as drifting; a daily sample (500 entities per group) on the existing health-check event keeps the record current
|
||||||
|
* Switching an entity from disabled to dual_write / shadow_read, or turning the Hook Bus back on, schedules a full drift fix 60 s later (`tmdo_drift_resync`)
|
||||||
|
* Auto-promotion requires a clean drift check within 2 days; shadow_read diffs are capped at 20 per key per hour
|
||||||
|
* `wp tmdo bridge-mode <entity> <mode>` (under the Promotion Guard); `member-backfill --all`; post / user backfill groups come from the registry, json groups included
|
||||||
|
* WooCommerce: the `post/wc_product` group is no longer registered — product meta stays native (retire existing tables with `bridge-restore-native post --group=wc_product --retire`)
|
||||||
|
* Sort-only searches drive from the flat table when every post of the type has a flat row (HivePress rating sort ~3.3 s → ~0.5–0.85 s on 100k listings)
|
||||||
|
* `wp tmdo cleanup-hp-transients --options` removes HivePress AddOn transients left in wp_options
|
||||||
|
* Fixed: entity backfill invented default values (0) for keys with no native row; doctor, term-comment-diagnose and bridge-status false alarms; member-cutover fatal on a refused transition
|
||||||
|
* Admin output escaping and logging clean-ups from the 2.1 audit
|
||||||
|
|
||||||
= 1.1.1 =
|
= 1.1.1 =
|
||||||
* Security: the public GET /wpdo/v1/listings endpoints returned every registered field (show_in_rest defaulted to true), including private values such as integration tokens and WooCommerce purchase notes. Fields are now private unless registered with show_in_rest => true, and protected (underscore) or credential-like keys are never exposed
|
* Security: the public GET /wpdo/v1/listings endpoints returned every registered field (show_in_rest defaulted to true), including private values such as integration tokens and WooCommerce purchase notes. Fields are now private unless registered with show_in_rest => true, and protected (underscore) or credential-like keys are never exposed
|
||||||
* Security: the listings endpoint no longer returns whole rows when no field is public, and only filters / sorts on public columns
|
* Security: the listings endpoint no longer returns whole rows when no field is public, and only filters / sorts on public columns
|
||||||
|
|||||||
Reference in New Issue
Block a user