From 763f705ac13603a393c9690c1439a8a2f8a1bf85 Mon Sep 17 00:00:00 2001 From: wpdev Date: Wed, 7 Oct 2026 10:12:26 +0800 Subject: [PATCH] fix(2meet-data-optimizer-hivepress-addon): 0.5.3 view-count flush keeps flat row and meta cache in sync flush_views_to_postmeta() adds warm-zone views back with a direct UPDATE, which the Hook Bus never sees: under dual_write/shadow_read the hp_listing_core.hp_view_count column drifted after every hourly batch and the (Redis) object cache kept the old count. After the UPDATE, drop the post's meta cache and, while native is still the source of truth, rebuild the entity's flat row with migrate_entity(). --- 2meet-data-optimizer-hivepress-addon.php | 4 +-- CHANGELOG.md | 14 +++++++++ includes/class-tmdo-listing-stats.php | 36 ++++++++++++++++++++++++ 3 files changed, 52 insertions(+), 2 deletions(-) diff --git a/2meet-data-optimizer-hivepress-addon.php b/2meet-data-optimizer-hivepress-addon.php index dc9502b..d4f2216 100644 --- a/2meet-data-optimizer-hivepress-addon.php +++ b/2meet-data-optimizer-hivepress-addon.php @@ -3,7 +3,7 @@ * Plugin Name: 2meet Data Optimizer — Hivepress AddOn * Plugin URI: https://2meet.io/2meet-data-optimizer/hivepress * Description: HivePress + 12 擴充整合:13 adapter (core/reviews/bookings/messages/memberships/requests/favorites/statistics/tags/seo/social-links/blocks/marketplace) + 7 HPCT interceptor + 5 query interceptor + admin tab + CLI namespace - * Version: 0.5.2 + * Version: 0.5.3 * Requires at least: 6.0 * Tested up to: 6.9.4 * Requires PHP: 8.1 @@ -24,7 +24,7 @@ if ( ! defined( 'ABSPATH' ) ) { exit; } -define( 'TMDO_HIVEPRESS_VERSION', '0.5.2' ); +define( 'TMDO_HIVEPRESS_VERSION', '0.5.3' ); define( 'TMDO_HIVEPRESS_PATH', plugin_dir_path( __FILE__ ) ); define( 'TMDO_HIVEPRESS_URL', plugin_dir_url( __FILE__ ) ); define( 'TMDO_HIVEPRESS_FILE', __FILE__ ); diff --git a/CHANGELOG.md b/CHANGELOG.md index 51c034a..99fcd80 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,20 @@ Versioning follows [Semantic Versioning](https://semver.org/). --- +## [0.5.3] — 2026-10-07 — 瀏覽數 flush 不再造成漂移 + +### Fixed + +- **`TMDO_Listing_Stats::flush_views_to_postmeta()` 寫完後同步扁平表與快取**:每小時把 warm zone 的瀏覽數 + 用原子 `UPDATE … meta_value + N` 加回 `hp_view_count`,繞過了 meta API:Hook Bus 看不到這次寫入, + dual_write/shadow_read 下 `hp_listing_core.hp_view_count` 每批落後一次(夜間 drift-check 每晚 diff), + 物件快取(Redis 下跨請求)也一直是舊值。現在 UPDATE 之後清掉該篇的 `post_meta` 快取, + 並在原生仍是真相時(同時寫原生與扁平)用 `TMDO_Entity_Migration_Engine::migrate_entity()` 重建那一列。 + `hp_view_count` 同時在 `hp_listing_core` 與 `hp_request_core`:只重建含這個 key、而且適用該篇 post type 的群組 + (不帶 post type 的 `get_field()` 只回最後登記的那組)。aeav_only 不動(扁平才是真相)。 + +--- + ## [0.5.2] — 2026-10-05 — attribute bridge 的 meta key ### Fixed diff --git a/includes/class-tmdo-listing-stats.php b/includes/class-tmdo-listing-stats.php index a17b955..612cadc 100644 --- a/includes/class-tmdo-listing-stats.php +++ b/includes/class-tmdo-listing-stats.php @@ -154,6 +154,8 @@ class TMDO_Listing_Stats { // Seed the key when it does not exist yet. if ( ! $updated ) { add_post_meta( $post_id, 'hp_view_count', $new_views, true ); + } else { + self::resync_view_count( $post_id ); } // Remove the warm entry after flush. @@ -164,6 +166,40 @@ class TMDO_Listing_Stats { return $flushed; } + /** + * The atomic UPDATE above bypasses the meta API: the object cache (persistent + * under Redis) keeps the old count, and the Hook Bus never sees the write, so in + * dual_write / shadow_read the flat column drifts by every flushed batch + * (drift-check diff on hp_view_count each night). Drop the cached meta and + * rebuild the entity's flat row from native — only while native is the source + * of truth (aeav_only keeps flat authoritative). + * + * @param int $post_id Listing post ID. + */ + private static function resync_view_count( int $post_id ): void { + wp_cache_delete( $post_id, 'post_meta' ); + if ( ! class_exists( 'TMDO_Mode_Manager' ) || ! class_exists( 'TMDO_Entity_Registry' ) || ! class_exists( 'TMDO_Entity_Migration_Engine' ) ) { + return; + } + if ( ! TMDO_Mode_Manager::writes_to_flat( 'post' ) || ! TMDO_Mode_Manager::writes_to_eav( 'post' ) ) { + return; + } + // hp_view_count lives in more than one group (hp_listing_core, hp_request_core): + // get_field() without a post type returns whichever registered last. Rebuild only + // the groups that hold the key and apply to this post's type. + $type = (string) get_post_type( $post_id ); + foreach ( TMDO_Entity_Registry::get_groups_for_type( 'post' ) as $group ) { + $types = TMDO_Entity_Registry::get_group_post_types( 'post', $group ); + if ( ! in_array( 'hp_view_count', TMDO_Entity_Registry::get_group_keys( 'post', $group ), true ) || ( $types && ! in_array( $type, $types, true ) ) ) { + continue; + } + TMDO_Entity_Migration_Engine::migrate_entity( 'post', $group, $post_id ); + if ( class_exists( 'TMDO_Cache_Orchestrator' ) ) { + TMDO_Cache_Orchestrator::invalidate( 'post', $post_id, $group ); + } + } + } + // ── Zone D: Expired Listing Archival ───────────────────────────────────── /**