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:
@@ -20,7 +20,7 @@
|
||||
* a single `class_exists('HivePress\\Core')` check — zero-cost fallback path
|
||||
* for sites that don't use HivePress.
|
||||
*
|
||||
* @package WP_Data_Optimizer
|
||||
* @package TMDO
|
||||
* @since 3.0.0
|
||||
*/
|
||||
|
||||
@@ -152,8 +152,15 @@ if ( ! class_exists( 'TMDO_HivePress_Detector' ) ) {
|
||||
return $cached;
|
||||
}
|
||||
|
||||
// Active-plugin set is the authoritative signal. HivePress addons
|
||||
// register via the `hivepress/v1/extensions` filter and publish no
|
||||
// per-addon class/const, so class_exists()/defined() alone only ever
|
||||
// detects core. We treat "addon plugin is active" as a first-class
|
||||
// detection signal alongside the class/const probe.
|
||||
$active = self::active_plugin_files();
|
||||
|
||||
// Short-circuit: if HivePress core is not present, no addon can be loaded.
|
||||
if ( ! self::probe_one( self::PROBES['hivepress'] ) ) {
|
||||
if ( ! self::probe_one( self::PROBES['hivepress'] ) && ! isset( $active['hivepress/hivepress.php'] ) ) {
|
||||
self::$memo = array();
|
||||
if ( function_exists( 'set_transient' ) ) {
|
||||
set_transient( self::CACHE_KEY, self::$memo, self::CACHE_TTL );
|
||||
@@ -163,8 +170,8 @@ if ( ! class_exists( 'TMDO_HivePress_Detector' ) ) {
|
||||
|
||||
$found = array();
|
||||
foreach ( self::PROBES as $slug => $probe ) {
|
||||
if ( self::probe_one( $probe ) ) {
|
||||
$found[ $slug ] = self::version_for( $probe );
|
||||
if ( self::probe_one( $probe ) || isset( $active[ $slug . '/' . $slug . '.php' ] ) ) {
|
||||
$found[ $slug ] = self::version_for( $slug, $probe );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -222,6 +229,31 @@ if ( ! class_exists( 'TMDO_HivePress_Detector' ) ) {
|
||||
|
||||
// ── Internal probes ─────────────────────────────────────────────────
|
||||
|
||||
/**
|
||||
* Active plugin file set (single-site + network), keyed by plugin file.
|
||||
*
|
||||
* Read straight from options so it works on `plugins_loaded` before
|
||||
* `wp-admin/includes/plugin.php` (`is_plugin_active`) is loaded.
|
||||
*
|
||||
* @return array<string,bool> Map of "dir/file.php" => true.
|
||||
*/
|
||||
private static function active_plugin_files(): array {
|
||||
$files = array();
|
||||
$site = function_exists( 'get_option' ) ? get_option( 'active_plugins' ) : false;
|
||||
if ( is_array( $site ) ) {
|
||||
foreach ( $site as $f ) {
|
||||
$files[ (string) $f ] = true;
|
||||
}
|
||||
}
|
||||
$network = function_exists( 'get_site_option' ) ? get_site_option( 'active_sitewide_plugins' ) : false;
|
||||
if ( is_array( $network ) ) {
|
||||
foreach ( array_keys( $network ) as $f ) {
|
||||
$files[ (string) $f ] = true;
|
||||
}
|
||||
}
|
||||
return $files;
|
||||
}
|
||||
|
||||
/**
|
||||
* Probe a single addon. Either the class OR the const must exist.
|
||||
*
|
||||
@@ -243,9 +275,13 @@ if ( ! class_exists( 'TMDO_HivePress_Detector' ) ) {
|
||||
/**
|
||||
* Best-effort version extraction. Empty string when no version available.
|
||||
*
|
||||
* Prefers the addon's version const; falls back to the `Version:` header
|
||||
* of the addon's main plugin file (HivePress addons publish no const).
|
||||
*
|
||||
* @param string $slug Addon slug (plugin dir name).
|
||||
* @param array{class:string, const:string, name:string} $probe Probe definition.
|
||||
*/
|
||||
private static function version_for( array $probe ): string {
|
||||
private static function version_for( string $slug, array $probe ): string {
|
||||
$const = (string) ( $probe['const'] ?? '' );
|
||||
if ( '' !== $const && defined( $const ) ) {
|
||||
$value = constant( $const );
|
||||
@@ -253,6 +289,19 @@ if ( ! class_exists( 'TMDO_HivePress_Detector' ) ) {
|
||||
return (string) $value;
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback: read the Version header from the addon's main plugin
|
||||
// file. HivePress addons expose no version const, so this is the
|
||||
// only version signal available for them.
|
||||
if ( defined( 'WP_PLUGIN_DIR' ) && function_exists( 'get_file_data' ) ) {
|
||||
$path = WP_PLUGIN_DIR . '/' . $slug . '/' . $slug . '.php';
|
||||
if ( is_readable( $path ) ) {
|
||||
$data = get_file_data( $path, array( 'Version' => 'Version' ) );
|
||||
if ( ! empty( $data['Version'] ) ) {
|
||||
return (string) $data['Version'];
|
||||
}
|
||||
}
|
||||
}
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user