fix(boundary): 核心不得無守衛呼叫 AddOn 的 TMDO_Listing_Stats
實機渲染時 Dashboard 分頁 fatal:"Class TMDO_Listing_Stats not found"。
該類別住在 hivepress-addon,核心有 6 處直呼,沒裝 AddOn 的站台會炸掉
Dashboard 與兩個 REST 端點(GET /listing/{id}、POST /listing/{id}/view)。
- TMDO_Zone_Warm 新增 VIEW_KEY / VIEW_TTL 常數(值與 AddOn 的
TMDO_Listing_Stats::VIEW_KEY 完全相同的 'wpdo_views',指向同一批列,
無資料遷移)
- CLI benchmark 改用核心常數
- REST 兩個 handler 改走新的 read_view_count() / bump_view_count():
AddOn 在場時仍委派過去(保留 hp_view_count postmeta fallback),
否則核心自己讀寫 warm 列
- wp tmdo cleanup --archive-expired 加守衛,AddOn 缺席時印 warning 並跳過
This commit is contained in:
@@ -798,12 +798,12 @@ class TMDO_CLI {
|
|||||||
if ( ! empty( $warm_posts ) ) {
|
if ( ! empty( $warm_posts ) ) {
|
||||||
// Seed warm zone entries so reads are non-trivial.
|
// Seed warm zone entries so reads are non-trivial.
|
||||||
foreach ( $warm_posts as $pid ) {
|
foreach ( $warm_posts as $pid ) {
|
||||||
TMDO_Zone_Warm::set( (int) $pid, TMDO_Listing_Stats::VIEW_KEY, '1', DAY_IN_SECONDS );
|
TMDO_Zone_Warm::set( (int) $pid, TMDO_Zone_Warm::VIEW_KEY, '1', DAY_IN_SECONDS );
|
||||||
}
|
}
|
||||||
|
|
||||||
$start = microtime( true );
|
$start = microtime( true );
|
||||||
foreach ( $warm_posts as $pid ) {
|
foreach ( $warm_posts as $pid ) {
|
||||||
TMDO_Zone_Warm::get( (int) $pid, TMDO_Listing_Stats::VIEW_KEY );
|
TMDO_Zone_Warm::get( (int) $pid, TMDO_Zone_Warm::VIEW_KEY );
|
||||||
}
|
}
|
||||||
$warm_ms = ( microtime( true ) - $start ) * 1000;
|
$warm_ms = ( microtime( true ) - $start ) * 1000;
|
||||||
|
|
||||||
@@ -1148,6 +1148,10 @@ class TMDO_CLI {
|
|||||||
WP_CLI::log( "Deleted {$warm_deleted} expired warm entries." );
|
WP_CLI::log( "Deleted {$warm_deleted} expired warm entries." );
|
||||||
|
|
||||||
if ( $archive_expired ) {
|
if ( $archive_expired ) {
|
||||||
|
// Listing archival is HivePress-specific and ships in that AddOn.
|
||||||
|
if ( ! class_exists( 'TMDO_Listing_Stats' ) ) {
|
||||||
|
WP_CLI::warning( '--archive-expired needs 2meet-data-optimizer-hivepress-addon; skipping.' );
|
||||||
|
} else {
|
||||||
WP_CLI::log( 'Archiving expired listing fields to Zone D...' );
|
WP_CLI::log( 'Archiving expired listing fields to Zone D...' );
|
||||||
$archived = TMDO_Listing_Stats::archive_expired_listings();
|
$archived = TMDO_Listing_Stats::archive_expired_listings();
|
||||||
WP_CLI::log( "Archived {$archived} fields from expired listings." );
|
WP_CLI::log( "Archived {$archived} fields from expired listings." );
|
||||||
@@ -1155,6 +1159,7 @@ class TMDO_CLI {
|
|||||||
$stats = TMDO_Zone_Archive::stats();
|
$stats = TMDO_Zone_Archive::stats();
|
||||||
WP_CLI::log( "Zone D total: {$stats['total_rows']} rows, {$stats['compressed_rows']} compressed." );
|
WP_CLI::log( "Zone D total: {$stats['total_rows']} rows, {$stats['compressed_rows']} compressed." );
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
WP_CLI::success( 'Cleanup complete.' );
|
WP_CLI::success( 'Cleanup complete.' );
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -646,7 +646,7 @@ class TMDO_REST_API {
|
|||||||
return $err;
|
return $err;
|
||||||
}
|
}
|
||||||
|
|
||||||
$views = TMDO_Listing_Stats::get_view_count( $post_id );
|
$views = self::read_view_count( $post_id );
|
||||||
|
|
||||||
return new WP_REST_Response(
|
return new WP_REST_Response(
|
||||||
array(
|
array(
|
||||||
@@ -730,8 +730,8 @@ class TMDO_REST_API {
|
|||||||
// Mark as counted for this IP/session.
|
// Mark as counted for this IP/session.
|
||||||
set_transient( $rl_key, 1, HOUR_IN_SECONDS );
|
set_transient( $rl_key, 1, HOUR_IN_SECONDS );
|
||||||
|
|
||||||
TMDO_Listing_Stats::increment_view( $post_id );
|
self::bump_view_count( $post_id );
|
||||||
$views = TMDO_Listing_Stats::get_view_count( $post_id );
|
$views = self::read_view_count( $post_id );
|
||||||
|
|
||||||
$response = new WP_REST_Response(
|
$response = new WP_REST_Response(
|
||||||
array(
|
array(
|
||||||
@@ -1642,4 +1642,37 @@ class TMDO_REST_API {
|
|||||||
$result = TMDO_Migration_Orchestrator::resume();
|
$result = TMDO_Migration_Orchestrator::resume();
|
||||||
return new WP_REST_Response( $result, ! empty( $result['ok'] ) ? 200 : 409 );
|
return new WP_REST_Response( $result, ! empty( $result['ok'] ) ? 200 : 409 );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read a post's view counter.
|
||||||
|
*
|
||||||
|
* Delegates to the HivePress AddOn when it is active, because that class
|
||||||
|
* adds an hp_view_count postmeta fallback for listings migrated before the
|
||||||
|
* warm zone existed. Without the AddOn — the normal case for a plain
|
||||||
|
* install — core reads its own warm row directly. Calling the AddOn class
|
||||||
|
* unconditionally used to fatal these endpoints on any site without it.
|
||||||
|
*
|
||||||
|
* @param int $post_id Post ID.
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
private static function read_view_count( int $post_id ): int {
|
||||||
|
if ( class_exists( 'TMDO_Listing_Stats' ) ) {
|
||||||
|
return (int) TMDO_Listing_Stats::get_view_count( $post_id );
|
||||||
|
}
|
||||||
|
return (int) ( TMDO_Zone_Warm::get( $post_id, TMDO_Zone_Warm::VIEW_KEY ) ?? 0 );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Increment a post's view counter.
|
||||||
|
*
|
||||||
|
* @param int $post_id Post ID.
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
private static function bump_view_count( int $post_id ): void {
|
||||||
|
if ( class_exists( 'TMDO_Listing_Stats' ) ) {
|
||||||
|
TMDO_Listing_Stats::increment_view( $post_id );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
TMDO_Zone_Warm::increment( $post_id, TMDO_Zone_Warm::VIEW_KEY, 1, TMDO_Zone_Warm::VIEW_TTL );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,6 +24,19 @@ if ( ! defined( 'ABSPATH' ) ) {
|
|||||||
*/
|
*/
|
||||||
class TMDO_Zone_Warm {
|
class TMDO_Zone_Warm {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Warm key used for per-post view counters.
|
||||||
|
*
|
||||||
|
* Owned by core because the row lives in this zone's table and core's admin,
|
||||||
|
* CLI and REST layers all read it. The HivePress AddOn's
|
||||||
|
* TMDO_Listing_Stats::VIEW_KEY carries the identical literal, so the two
|
||||||
|
* address the same rows — nothing to migrate either way.
|
||||||
|
*/
|
||||||
|
const VIEW_KEY = 'wpdo_views';
|
||||||
|
|
||||||
|
/** TTL applied when core increments the view counter itself. */
|
||||||
|
const VIEW_TTL = DAY_IN_SECONDS;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the warm table name.
|
* Get the warm table name.
|
||||||
*/
|
*/
|
||||||
|
|||||||
Reference in New Issue
Block a user