fix(hivepress): detector active-plugin 偵測 + 4 個 interceptor 改繼承核心基底(F2/F3/F4)

F3 detector(A v3.4.5):HivePress addon 不暴露任何 per-addon class/const,
   它們是透過 add_filter('hivepress/v1/extensions') 註冊目錄,所以原本的
   class_exists / defined 偵測永遠只認得 core → 反 EAV 覆蓋率卡在 1/13。
   改以 get_option('active_plugins') 為第一級訊號(新增 active_plugin_files()),
   version_for() 對 addon 改讀其主檔 Version: header。覆蓋率回到 7/13。

F2 interceptor:reviews / messages / memberships / requests 改繼承核心的
   TMDO_Standard_Post_Interceptor,573 → 344 行。FIELD_MAP 由 private
   提升為 public(late static binding 從基底讀取)。
   bootstrap 的 require 迴圈加核心版本守衛:這 4 個檔案在舊核心下會於
   parse 階段就 fatal,class_exists 守衛來不及。

F4 listing-stats:view 計數改用 Zone_Warm::increment() 原子遞增,
   flush 改原子 UPDATE,消除 get()+set() 的 lost-update race。

F5:主檔補 TablePrefix header(打包終檢 §10 schema drift 主路徑)。

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 06:07:39 +08:00
parent e3ede89197
commit b96b041445
8 changed files with 240 additions and 414 deletions
+17 -21
View File
@@ -2,7 +2,7 @@
/**
* Listing stats integration for Zone B view counting.
*
* @package WP_Data_Optimizer
* @package TMDO
*/
if ( ! defined( 'ABSPATH' ) ) {
@@ -93,8 +93,7 @@ class TMDO_Listing_Stats {
* @param int $post_id Listing post ID.
*/
public static function increment_view( int $post_id ): void {
$current = (int) TMDO_Zone_Warm::get( $post_id, self::VIEW_KEY );
TMDO_Zone_Warm::set( $post_id, self::VIEW_KEY, (string) ( $current + 1 ), self::VIEW_TTL );
TMDO_Zone_Warm::increment( $post_id, self::VIEW_KEY, 1, self::VIEW_TTL );
}
/**
@@ -136,29 +135,26 @@ class TMDO_Listing_Stats {
return 0;
}
// Batch-fetch existing hp_view_count for all post IDs in one query.
$post_ids = array_map( 'intval', array_column( $rows, 'post_id' ) );
$placeholders = implode( ',', array_fill( 0, count( $post_ids ), '%d' ) );
$existing_rows = $wpdb->get_results(
$wpdb->prepare(
"SELECT post_id, meta_value FROM {$wpdb->postmeta} WHERE meta_key = 'hp_view_count' AND post_id IN ({$placeholders})", // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared,WordPress.DB.PreparedSQL.InterpolatedNotPrepared,WordPress.DB.PreparedSQLPlaceholders.UnfinishedPrepare -- $wpdb->postmeta is core. phpcs:ignore WPDO.AntiEAV.no-direct-postmeta-select -- Listing Stats: Zone B → postmeta view-count sync path.
...$post_ids
),
ARRAY_A
);
$existing_map = array();
foreach ( $existing_rows as $er ) {
$existing_map[ (int) $er['post_id'] ] = (int) $er['meta_value'];
}
$flushed = 0;
foreach ( $rows as $row ) {
$post_id = (int) $row['post_id'];
$new_views = (int) $row['meta_value'];
// Add to existing postmeta total.
$existing = $existing_map[ $post_id ] ?? 0;
update_post_meta( $post_id, 'hp_view_count', $existing + $new_views );
// Atomic increment: avoids the read-modify-write race that could lose
// concurrent view increments arriving between our batch-read and the write.
// phpcs:ignore WordPress.DB.DirectDatabaseQuery,WordPress.DB.DirectDatabaseQuery.NoCaching -- WPDO.AntiEAV.no-direct-postmeta-update: view-count sync, no meta API equivalent for atomic add.
$updated = $wpdb->query(
$wpdb->prepare(
"UPDATE `{$wpdb->postmeta}` SET meta_value = meta_value + %d WHERE post_id = %d AND meta_key = 'hp_view_count'",
$new_views,
$post_id
)
);
// Seed the key when it does not exist yet.
if ( ! $updated ) {
add_post_meta( $post_id, 'hp_view_count', $new_views, true );
}
// Remove the warm entry after flush.
TMDO_Zone_Warm::delete( $post_id, self::VIEW_KEY );