From 8a1c9c03534047b865474ea1d592986356403281 Mon Sep 17 00:00:00 2001 From: wpdev Date: Sat, 26 Sep 2026 00:14:18 +0800 Subject: [PATCH] refactor(2meet-data-optimizer): remove HPCT legacy from core - Feature flags keep only the live AddOn modules (wc_orders, latepoint) as ADDON_MODULES / addon_modules(); drop map_hpct_status() and the 7 HivePress HPCT modules whose interceptors were removed in PR-014 - Remove HPCT detection/notice (Compatibility, core), the admin HPCT import tab and status row, CLI import-hpct, the 7 advisor rules for dead modules, and the removed interceptors from COEXIST_WHITELIST - Verify: NoHpctLegacyTest guard; core unit 635 / integration 449, HP 145/49, WC 10/22 OK; all sites have every module idle and never imported HPCT - PR: PR-020c --- admin/class-tmdo-admin.php | 103 +----------------- admin/class-tmdo-help-tabs.php | 3 +- cli/class-tmdo-cli.php | 70 +----------- .../advisor/class-tmdo-module-detector.php | 1 - includes/advisor/class-tmdo-module-rules.php | 46 +------- includes/class-tmdo-compatibility.php | 59 +--------- includes/class-tmdo-core.php | 41 ------- includes/class-tmdo-feature-flags.php | 39 +------ includes/class-tmdo-hook-bus-bridge.php | 7 -- .../snapshots/class-tmdo-snapshot-manager.php | 2 +- tests/unit/Advisor/FSMAdvisorTest.php | 40 +++---- tests/unit/Advisor/ModuleDetectorTest.php | 16 +-- tests/unit/NoHpctLegacyTest.php | 61 +++++++++++ 13 files changed, 110 insertions(+), 378 deletions(-) create mode 100644 tests/unit/NoHpctLegacyTest.php diff --git a/admin/class-tmdo-admin.php b/admin/class-tmdo-admin.php index ecc67bf..e11354d 100644 --- a/admin/class-tmdo-admin.php +++ b/admin/class-tmdo-admin.php @@ -783,11 +783,6 @@ class TMDO_Admin { $tab = 'dashboard'; } - // Show HPCT Import tab only when HPCT is detected. - if ( TMDO_Compatibility::should_show_hpct_notice() ) { - $tabs['hpct-import'] = __( 'HPCT 匯入', '2meet-data-optimizer' ); - } - // v2.8.1: red-dot badge on tabs that need operator attention. $needs_dot = array(); if ( class_exists( 'TMDO_Migration_Orchestrator' ) ) { @@ -811,7 +806,7 @@ class TMDO_Admin { ), 'wizards' => array( 'label' => esc_html__( '🧙 遷移精靈', '2meet-data-optimizer' ), - 'tabs' => array( 'migration-wizard', 'post-migration-wizard', 'hpct-import' ), + 'tabs' => array( 'migration-wizard', 'post-migration-wizard' ), ), 'stress' => array( 'label' => esc_html__( '⚡ 壓力測試', '2meet-data-optimizer' ), @@ -939,9 +934,6 @@ class TMDO_Admin { case 'rest-api': self::render_rest_api(); break; - case 'hpct-import': - self::render_hpct_import(); - break; case 'hivepress': if ( class_exists( 'TMDO_Admin_HivePress' ) ) { TMDO_Admin_HivePress::render(); @@ -1121,20 +1113,6 @@ class TMDO_Admin { Active' : 'N/A' ); ?> - - - - Imported'; - } elseif ( $compat['hpct_active'] ) { - echo 'Needs Import'; - } else { - echo 'N/A'; - } - ?> - - @@ -1169,11 +1147,11 @@ class TMDO_Admin {

-

HPCT Modules

+

AddOn Modules

- $state ) : ?> + $state ) : ?> @@ -2717,79 +2695,6 @@ wpdo.getListings({ per_page: 3 }).then(r => console.log(r));'

' - . esc_html__( 'HPCT 匯入需要啟用 2meet-data-optimizer-hivepress-addon。', '2meet-data-optimizer' ) - . '

'; - return; - } - - // Handle import action. - if ( isset( $_POST['wpdo_run_import'] ) && check_admin_referer( 'wpdo_hpct_import' ) ) { - $result = TMDO_HPCT_Import::run(); - if ( is_wp_error( $result ) ) { - echo '

' . esc_html( $result->get_error_message() ) . '

'; - } else { - echo '

' . esc_html__( 'HPCT 匯入成功!建議停用 HP Custom Tables 外掛。', '2meet-data-optimizer' ) . '

'; - } - } - - $can_import = TMDO_HPCT_Import::can_import(); - $is_imported = TMDO_HPCT_Import::is_imported(); - - ?> -

- - -
-

-
- -

- - -

-
- - - - - - - - - - - - - - - - -
- -
- - -
- - -
-

-
- - console.log(r));' '; foreach ( $all as $m ) { printf( diff --git a/admin/class-tmdo-help-tabs.php b/admin/class-tmdo-help-tabs.php index 8aa3066..3da8749 100644 --- a/admin/class-tmdo-help-tabs.php +++ b/admin/class-tmdo-help-tabs.php @@ -107,7 +107,7 @@ class TMDO_Help_Tabs { private static function content_dashboard(): string { return '

' . esc_html__( '儀表板顯示:', '2meet-data-optimizer' ) . '

' . '
    ' - . '
  • ' . esc_html__( 'System Overview — DB 引擎、HivePress、HPCT、Object Cache 是否啟用', '2meet-data-optimizer' ) . '
  • ' + . '
  • ' . esc_html__( 'System Overview — DB 引擎、HivePress、Object Cache 是否啟用', '2meet-data-optimizer' ) . '
  • ' . '
  • ' . esc_html__( 'Zone 行數統計 — Hot/Warm/Cold/Archive 各自累積多少資料', '2meet-data-optimizer' ) . '
  • ' . '
  • ' . esc_html__( 'Module 狀態 — 每個 module 在 7-state FSM 哪一格', '2meet-data-optimizer' ) . '
  • ' . '
  • ' . esc_html__( 'Warm zone live view — 哪些 view counts / TTL 進來、24h 快過期數', '2meet-data-optimizer' ) . '
  • ' @@ -173,7 +173,6 @@ class TMDO_Help_Tabs { . '

    ' . esc_html__( '常見原因:', '2meet-data-optimizer' ) . '

    ' . '
      ' . '
    • ' . esc_html__( 'Hook Bus 啟用(wpdo_hook_bus_enabled = 1)+ legacy interceptors 還沒卸載', '2meet-data-optimizer' ) . '
    • ' - . '
    • ' . esc_html__( 'HPCT (HP Custom Tables) plugin 還沒移除 — 與 WPDO 同時攔截', '2meet-data-optimizer' ) . '
    • ' . '
    ' . '

    ' . esc_html__( '解法:先看 conflict-scan 詳情,必要時用 wp wpdo bridge-set off 暫停 Hook Bus 直到清理完。', '2meet-data-optimizer' ) . '

    '; } diff --git a/cli/class-tmdo-cli.php b/cli/class-tmdo-cli.php index da7b033..6d193ef 100644 --- a/cli/class-tmdo-cli.php +++ b/cli/class-tmdo-cli.php @@ -42,7 +42,6 @@ class TMDO_CLI { $compat = TMDO_Compatibility::check(); WP_CLI::log( 'HivePress: ' . ( $compat['hivepress'] ? 'Active' : 'Not found' ) ); - WP_CLI::log( 'HP Custom Tables: ' . self::format_hpct_status( $compat ) ); WP_CLI::log( 'Object Cache: ' . ( wp_using_ext_object_cache() ? 'External' : 'Built-in' ) ); WP_CLI::log( '' ); @@ -57,10 +56,10 @@ class TMDO_CLI { WP_CLI::log( 'Module States:' ); - $hpct_flags = TMDO_Feature_Flags::hpct_modules(); - if ( ! empty( $hpct_flags ) ) { - WP_CLI::log( ' [HPCT Modules]' ); - foreach ( $hpct_flags as $module => $state ) { + $addon_flags = TMDO_Feature_Flags::addon_modules(); + if ( ! empty( $addon_flags ) ) { + WP_CLI::log( ' [AddOn Modules]' ); + foreach ( $addon_flags as $module => $state ) { WP_CLI::log( " {$module}: {$state}" ); } } @@ -668,51 +667,6 @@ class TMDO_CLI { WP_CLI::success( "Module {$module} disabled (idle)." ); } - /** - * Import settings from HP Custom Tables. - * - * ## EXAMPLES - * - * wp wpdo import-hpct - * - * @param array $args Positional arguments. - * @param array $assoc_args Associative arguments. - * @return void - * - * @subcommand import-hpct - */ - public function import_hpct( $args, $assoc_args ): void { // phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundAfterLastUsed - // HPCT is a HivePress-family plugin; the importer ships in that AddOn. - if ( ! class_exists( 'TMDO_HPCT_Import' ) ) { - WP_CLI::error( 'import-hpct needs 2meet-data-optimizer-hivepress-addon to be active.' ); - } - - if ( TMDO_HPCT_Import::is_imported() ) { - WP_CLI::warning( 'HPCT settings have already been imported.' ); - return; - } - - if ( ! TMDO_HPCT_Import::can_import() ) { - WP_CLI::error( 'HP Custom Tables plugin not detected or already imported.' ); - } - - // Show preview. - $preview_data = TMDO_HPCT_Import::preview(); - if ( ! empty( $preview_data['modules'] ) ) { - WP_CLI::log( 'Import preview:' ); - WP_CLI\Utils\format_items( 'table', $preview_data['modules'], array( 'module', 'hpct_status', 'wpdo_state' ) ); - } - - WP_CLI::confirm( 'Proceed with import?' ); - - $result = TMDO_HPCT_Import::run(); - if ( is_wp_error( $result ) ) { - WP_CLI::error( $result->get_error_message() ); - } - - WP_CLI::success( 'HPCT settings imported successfully. You can now deactivate HP Custom Tables.' ); - } - /** * Run performance benchmark. * @@ -1430,22 +1384,6 @@ class TMDO_CLI { } } - /** - * Format the HPCT status string for display. - * - * @param array $compat Compatibility check result array. - * @return string Human-readable HPCT status. - */ - private static function format_hpct_status( array $compat ): string { - if ( $compat['hpct_active'] && $compat['hpct_imported'] ) { - return 'Active (Imported)'; - } - if ( $compat['hpct_active'] ) { - return 'Active (Not imported — run `wp wpdo import-hpct`)'; - } - return 'Not found'; - } - /** * Create the appropriate migration instance for a module name. * diff --git a/includes/advisor/class-tmdo-module-detector.php b/includes/advisor/class-tmdo-module-detector.php index b8727c4..b3c00ba 100644 --- a/includes/advisor/class-tmdo-module-detector.php +++ b/includes/advisor/class-tmdo-module-detector.php @@ -284,7 +284,6 @@ class TMDO_Module_Detector { $active = match ( $plugin ) { 'hivepress' => TMDO_Compatibility::is_hivepress_active(), 'woocommerce' => TMDO_Compatibility::is_woocommerce_active(), - 'hpct' => TMDO_Compatibility::is_hpct_active(), 'latepoint' => TMDO_Compatibility::is_latepoint_active(), default => false, }; diff --git a/includes/advisor/class-tmdo-module-rules.php b/includes/advisor/class-tmdo-module-rules.php index fd9011e..c998a21 100644 --- a/includes/advisor/class-tmdo-module-rules.php +++ b/includes/advisor/class-tmdo-module-rules.php @@ -29,52 +29,10 @@ if ( ! defined( 'ABSPATH' ) ) { class TMDO_Module_Rules { /** - * Default rules for the 15 known modules. Use `get()` to apply filter. + * Default rules for the 8 known modules. Use `get()` to apply filter. */ private const DEFAULT_RULES = array( - // ─── HPCT modules(HivePress + HPCT)──────────────────────────── - 'reviews' => array( - 'compat_required' => array( 'hivepress' ), - 'post_type_required' => 'hp_review', - 'min_post_count' => 100, - 'description' => '若使用 HivePress reviews 且累積評論 ≥ 100 條,啟用後可顯著降低 listing 查詢的 JOIN 成本。', - ), - 'messages' => array( - 'compat_required' => array( 'hivepress' ), - 'post_type_required' => 'hp_message_thread', - 'min_post_count' => 50, - 'description' => 'HivePress messages 累積對話數 ≥ 50 時,啟用 module 可加速 inbox / unread count 查詢。', - ), - 'favorites' => array( - 'compat_required' => array( 'hivepress' ), - 'post_type_required' => 'hp_favorite', - 'min_post_count' => 200, - 'description' => '使用者 favorite 累積 ≥ 200 條時,啟用 module 把 favorite meta 從 wp_postmeta 搬出。', - ), - 'memberships' => array( - 'compat_required' => array( 'hivepress' ), - 'post_type_required' => 'hp_membership', - 'min_post_count' => 50, - 'description' => 'HivePress memberships 啟用且 ≥ 50 條訂閱時,membership 過期檢查會更快。', - ), - 'statistics' => array( - 'compat_required' => array( 'hivepress' ), - 'post_type_required' => 'hp_listing', - 'min_post_count' => 500, - 'description' => 'Listing ≥ 500 條時,view_count / favorite_count 等高頻統計搬到 stats module 可大幅減少 wp_postmeta 寫入。', - ), - 'requests' => array( - 'compat_required' => array( 'hivepress' ), - 'post_type_required' => 'hp_request', - 'min_post_count' => 50, - 'description' => 'HivePress requests / quotes 累積 ≥ 50 條時建議啟用。', - ), - 'listing_meta' => array( - 'compat_required' => array( 'hivepress' ), - 'post_type_required' => 'hp_listing', - 'min_post_count' => 100, - 'description' => '所有 listing meta 集中管理;listing ≥ 100 時可省下大量 postmeta JOIN。', - ), + // ─── AddOn modules ────────────────────────────────────────────── 'wc_orders' => array( 'compat_required' => array( 'woocommerce' ), 'post_type_required' => 'shop_order', diff --git a/includes/class-tmdo-compatibility.php b/includes/class-tmdo-compatibility.php index a9e0d1c..cb4ac92 100644 --- a/includes/class-tmdo-compatibility.php +++ b/includes/class-tmdo-compatibility.php @@ -37,57 +37,23 @@ class TMDO_Compatibility { } self::$detected = array( - 'hpct_active' => self::is_hpct_active(), - 'hpct_imported' => self::is_hpct_imported(), - 'hivepress' => self::is_hivepress_active(), - 'woocommerce' => self::is_woocommerce_active(), + 'hivepress' => self::is_hivepress_active(), + 'woocommerce' => self::is_woocommerce_active(), ); return self::$detected; } - /** - * Can WPDO register its HPCT-inherited module interceptors? - * - * True when: - * - hp-custom-tables is NOT active, OR - * - hp-custom-tables IS active but already imported into WPDO. - */ - public static function can_register_hpct_hooks(): bool { - $compat = self::check(); - - // HPCT not active → WPDO can freely register. - if ( ! $compat['hpct_active'] ) { - return true; - } - - // HPCT is active but already imported → WPDO takes over. - if ( $compat['hpct_imported'] ) { - return true; - } - - // HPCT is active and NOT imported → defer to HPCT. - return false; - } - /** * Can WPDO register zone-specific interceptors (hot/warm/cold/archive)? * * Zone interceptors are always safe to register — they operate on - * WPDO's own tables and do not conflict with HPCT. + * WPDO's own tables. */ public static function can_register_zone_hooks(): bool { return true; } - /** - * Should WPDO show an admin notice about HPCT import? - */ - public static function should_show_hpct_notice(): bool { - $compat = self::check(); - return $compat['hpct_active'] && ! $compat['hpct_imported']; - } - /** * Is HivePress core active? */ @@ -113,23 +79,4 @@ class TMDO_Compatibility { || defined( 'LATEPOINT_VERSION' ) || function_exists( 'latepoint_get_settings' ); } - - // ── Detection Methods ──────────────────────────────────────────────── - - /** - * Is HP Custom Tables plugin active (loaded)? - * - * Checks for the HPCT_Loader class, which is always loaded - * when hp-custom-tables is active. - */ - public static function is_hpct_active(): bool { - return class_exists( 'HPCT_Loader' ) || defined( 'HPCT_VERSION' ); - } - - /** - * Has HPCT been imported into WPDO? - */ - private static function is_hpct_imported(): bool { - return (bool) get_option( 'wpdo_hpct_imported', false ); - } } diff --git a/includes/class-tmdo-core.php b/includes/class-tmdo-core.php index 4a4a459..cc53a12 100644 --- a/includes/class-tmdo-core.php +++ b/includes/class-tmdo-core.php @@ -95,11 +95,6 @@ class TMDO_Core { // Cache Layer hooks (Zone C prefetch + save_post warming). TMDO_Cache_Layer::register_hooks(); - // Register HPCT-inherited module interceptors if allowed. - if ( TMDO_Compatibility::can_register_hpct_hooks() ) { - $this->register_hpct_interceptors(); - } - // Zone interceptors are always safe to register. if ( TMDO_Compatibility::can_register_zone_hooks() ) { $this->register_zone_hooks(); @@ -130,11 +125,6 @@ class TMDO_Core { // Schedule cron events. $this->schedule_cron(); - // Admin notice for HPCT import. - if ( is_admin() && TMDO_Compatibility::should_show_hpct_notice() ) { - add_action( 'admin_notices', array( $this, 'render_hpct_notice' ) ); - } - // v2.6.6: async entity backfill cron handler. add_action( 'wpdo_entity_backfill_batch', array( $this, 'run_entity_backfill_batch' ), 10, 2 ); @@ -248,16 +238,6 @@ class TMDO_Core { do_action( 'wpdo_register_entity_fields', TMDO_Entity_Registry::class ); } - /** - * Register HPCT-inherited module interceptors and query interceptors. - */ - private function register_hpct_interceptors(): void { - // 7 HPCT-era meta interceptors 已搬到 2meet-data-optimizer-hivepress-addon。 - // 1 LatePoint interceptor 已搬到 2meet-data-optimizer-latepoint-addon。 - // 5 query interceptors 已搬到 2meet-data-optimizer-hivepress-addon。 - // 此方法保留為空殼以保持 ABI 相容;AddOn 各自於自身 bootstrap 內 register_hooks。 - } - /** * Register zone-specific hooks. */ @@ -555,27 +535,6 @@ class TMDO_Core { TMDO_Zone_Archive::sweep(); } - /** - * Render admin notice when hp-custom-tables is detected but not imported. - */ - public function render_hpct_notice(): void { - $import_url = admin_url( 'tools.php?page=wp-data-optimizer&tab=hpct-import' ); - ?> -
    -

    - WP Data Optimizer: - ' . esc_html__( 'HPCT 匯入頁面', '2meet-data-optimizer' ) . '' - ); - ?> -

    -
    - */ - public static function hpct_modules(): array { + public static function addon_modules(): array { $all = self::all(); - return array_intersect_key( $all, array_flip( self::HPCT_MODULES ) ); + return array_intersect_key( $all, array_flip( self::ADDON_MODULES ) ); } /** @@ -326,23 +318,4 @@ class TMDO_Feature_Flags { $all = self::all(); return array_intersect_key( $all, array_flip( self::ZONE_MODULES ) ); } - - /** - * Map an HPCT feature flag status to a WPDO state. - * - * Used during HPCT import to translate HPCT's 4-state model - * to WPDO's 7-state model. - * - * @param string $hpct_status HPCT status (disabled/migrating/verified/enabled). - * @return string WPDO state. - */ - public static function map_hpct_status( string $hpct_status ): string { - return match ( $hpct_status ) { - 'disabled' => 'idle', - 'migrating' => 'backfill', - 'verified' => 'cutover', - 'enabled' => 'complete', - default => 'idle', - }; - } } diff --git a/includes/class-tmdo-hook-bus-bridge.php b/includes/class-tmdo-hook-bus-bridge.php index 6436db4..d70f6e1 100644 --- a/includes/class-tmdo-hook-bus-bridge.php +++ b/includes/class-tmdo-hook-bus-bridge.php @@ -98,13 +98,6 @@ final class TMDO_Hook_Bus_Bridge { * @var string[] */ private const COEXIST_WHITELIST = array( - 'TMDO_Reviews_Interceptor', - 'TMDO_Messages_Interceptor', - 'TMDO_Favorites_Interceptor', - 'TMDO_Memberships_Interceptor', - 'TMDO_Statistics_Interceptor', - 'TMDO_Requests_Interceptor', - 'TMDO_Listing_Meta_Interceptor', 'TMDO_WC_Orders_Interceptor', 'TMDO_LatePoint_Interceptor', 'TMDO_Sync_Bridge', diff --git a/includes/snapshots/class-tmdo-snapshot-manager.php b/includes/snapshots/class-tmdo-snapshot-manager.php index 0787204..a4ec226 100644 --- a/includes/snapshots/class-tmdo-snapshot-manager.php +++ b/includes/snapshots/class-tmdo-snapshot-manager.php @@ -424,7 +424,7 @@ class TMDO_Snapshot_Manager { return array(); } $out = array(); - $modules = array_merge( TMDO_Feature_Flags::HPCT_MODULES, TMDO_Feature_Flags::ZONE_MODULES ); + $modules = array_merge( TMDO_Feature_Flags::ADDON_MODULES, TMDO_Feature_Flags::ZONE_MODULES ); foreach ( $modules as $m ) { $out[ $m ] = TMDO_Feature_Flags::get( $m ); } diff --git a/tests/unit/Advisor/FSMAdvisorTest.php b/tests/unit/Advisor/FSMAdvisorTest.php index 0097811..8302410 100644 --- a/tests/unit/Advisor/FSMAdvisorTest.php +++ b/tests/unit/Advisor/FSMAdvisorTest.php @@ -65,65 +65,65 @@ class FSMAdvisorTest extends TestCase { } public function test_idle_state_returns_HOLD(): void { - $this->set_module_state( 'reviews', 'idle' ); - $advice = WPDO_FSM_Advisor::advise( 'reviews' ); + $this->set_module_state( 'wc_orders', 'idle' ); + $advice = WPDO_FSM_Advisor::advise( 'wc_orders' ); $this->assertSame( 'HOLD', $advice['action'] ); $this->assertSame( 'info', $advice['level'] ); } public function test_complete_state_returns_HOLD(): void { - $this->set_module_state( 'reviews', 'complete' ); - $advice = WPDO_FSM_Advisor::advise( 'reviews' ); + $this->set_module_state( 'wc_orders', 'complete' ); + $advice = WPDO_FSM_Advisor::advise( 'wc_orders' ); $this->assertSame( 'HOLD', $advice['action'] ); } public function test_dual_write_with_short_soak_returns_WAIT(): void { // In dual_write 0 days < 1 day min soak. - $this->set_module_state( 'reviews', 'dual_write', 0 ); - $advice = WPDO_FSM_Advisor::advise( 'reviews' ); + $this->set_module_state( 'wc_orders', 'dual_write', 0 ); + $advice = WPDO_FSM_Advisor::advise( 'wc_orders' ); $this->assertSame( 'WAIT', $advice['action'] ); $this->assertGreaterThanOrEqual( 1, $advice['days_remaining'] ); } public function test_dual_write_after_min_soak_returns_PROMOTE(): void { - $this->set_module_state( 'reviews', 'dual_write', 2 ); - $advice = WPDO_FSM_Advisor::advise( 'reviews' ); + $this->set_module_state( 'wc_orders', 'dual_write', 2 ); + $advice = WPDO_FSM_Advisor::advise( 'wc_orders' ); $this->assertSame( 'PROMOTE', $advice['action'] ); $this->assertSame( 'backfill', $advice['next_state'] ); } public function test_verify_with_long_soak_returns_PROMOTE(): void { // verify needs 7 days; 10 days = should promote. - $this->set_module_state( 'reviews', 'verify', 10 ); - $advice = WPDO_FSM_Advisor::advise( 'reviews' ); + $this->set_module_state( 'wc_orders', 'verify', 10 ); + $advice = WPDO_FSM_Advisor::advise( 'wc_orders' ); $this->assertSame( 'PROMOTE', $advice['action'] ); $this->assertSame( 'cutover', $advice['next_state'] ); } public function test_verify_with_short_soak_returns_WAIT(): void { - $this->set_module_state( 'reviews', 'verify', 3 ); - $advice = WPDO_FSM_Advisor::advise( 'reviews' ); + $this->set_module_state( 'wc_orders', 'verify', 3 ); + $advice = WPDO_FSM_Advisor::advise( 'wc_orders' ); $this->assertSame( 'WAIT', $advice['action'] ); $this->assertSame( 4, $advice['days_remaining'] ); } public function test_cleanup_with_short_wash_returns_WAIT(): void { - $this->set_module_state( 'reviews', 'cleanup', 1 ); - $advice = WPDO_FSM_Advisor::advise( 'reviews' ); + $this->set_module_state( 'wc_orders', 'cleanup', 1 ); + $advice = WPDO_FSM_Advisor::advise( 'wc_orders' ); $this->assertSame( 'WAIT', $advice['action'] ); $this->assertSame( 2, $advice['days_remaining'] ); } public function test_cleanup_after_wash_returns_PROMOTE(): void { - $this->set_module_state( 'reviews', 'cleanup', 5 ); - $advice = WPDO_FSM_Advisor::advise( 'reviews' ); + $this->set_module_state( 'wc_orders', 'cleanup', 5 ); + $advice = WPDO_FSM_Advisor::advise( 'wc_orders' ); $this->assertSame( 'PROMOTE', $advice['action'] ); $this->assertSame( 'complete', $advice['next_state'] ); } public function test_advice_metrics_include_state_and_soak(): void { - $this->set_module_state( 'reviews', 'dual_write', 5 ); - $advice = WPDO_FSM_Advisor::advise( 'reviews' ); + $this->set_module_state( 'wc_orders', 'dual_write', 5 ); + $advice = WPDO_FSM_Advisor::advise( 'wc_orders' ); $this->assertSame( 'dual_write', $advice['metrics']['state'] ); $this->assertSame( 5, $advice['metrics']['days_in_state'] ); $this->assertSame( 1, $advice['metrics']['min_soak_days'] ); @@ -132,8 +132,8 @@ class FSMAdvisorTest extends TestCase { public function test_advise_all_returns_map_for_all_modules(): void { $advice = WPDO_FSM_Advisor::advise_all(); $this->assertNotEmpty( $advice ); - // All known HPCT + zone modules should be present (default idle). - foreach ( WPDO_Feature_Flags::HPCT_MODULES as $m ) { + // All known AddOn + zone modules should be present (default idle). + foreach ( WPDO_Feature_Flags::ADDON_MODULES as $m ) { $this->assertArrayHasKey( $m, $advice ); } } diff --git a/tests/unit/Advisor/ModuleDetectorTest.php b/tests/unit/Advisor/ModuleDetectorTest.php index 6be0b0c..c797caf 100644 --- a/tests/unit/Advisor/ModuleDetectorTest.php +++ b/tests/unit/Advisor/ModuleDetectorTest.php @@ -67,15 +67,15 @@ class ModuleDetectorTest extends TestCase { public function test_module_rules_known_modules_count(): void { $modules = WPDO_Module_Rules::known_modules(); - $this->assertGreaterThanOrEqual( 14, count( $modules ), '預期 ≥ 14 個 module(9 HPCT + 6 zone - 1 dup)' ); - $this->assertContains( 'reviews', $modules ); + $this->assertGreaterThanOrEqual( 8, count( $modules ), '預期 ≥ 8 個 module(2 AddOn + 6 zone)' ); + $this->assertContains( 'wc_orders', $modules ); $this->assertContains( 'warm', $modules ); $this->assertContains( 'archive', $modules ); $this->assertContains( 'hot_hp_listing', $modules ); } public function test_module_rule_for_module_returns_array(): void { - $rule = WPDO_Module_Rules::for_module( 'reviews' ); + $rule = WPDO_Module_Rules::for_module( 'wc_orders' ); $this->assertIsArray( $rule ); $this->assertArrayHasKey( 'compat_required', $rule ); $this->assertArrayHasKey( 'description', $rule ); @@ -86,9 +86,9 @@ class ModuleDetectorTest extends TestCase { } public function test_detector_skip_when_module_not_idle(): void { - // Set reviews to dual_write. - WPDO_Feature_Flags::set( 'reviews', 'dual_write' ); - $r = WPDO_Module_Detector::detect_one( 'reviews' ); + // Set wc_orders to dual_write. + WPDO_Feature_Flags::set( 'wc_orders', 'dual_write' ); + $r = WPDO_Module_Detector::detect_one( 'wc_orders' ); $this->assertSame( 'skip', $r['recommendation'] ); $this->assertFalse( $r['available'] ); $this->assertNotEmpty( $r['blockers'] ); @@ -123,9 +123,9 @@ class ModuleDetectorTest extends TestCase { } public function test_detector_hivepress_required_blocks_when_inactive(): void { - // reviews requires hivepress; Compatibility class isn't loaded in this test. + // hot_hp_listing requires hivepress; Compatibility class isn't loaded in this test. // Without Compatibility class, the helper returns the full required list as missing. - $r = WPDO_Module_Detector::detect_one( 'reviews' ); + $r = WPDO_Module_Detector::detect_one( 'hot_hp_listing' ); $this->assertSame( 'skip', $r['recommendation'] ); $this->assertNotEmpty( $r['blockers'] ); } diff --git a/tests/unit/NoHpctLegacyTest.php b/tests/unit/NoHpctLegacyTest.php new file mode 100644 index 0000000..379e59d --- /dev/null +++ b/tests/unit/NoHpctLegacyTest.php @@ -0,0 +1,61 @@ + array( 'wpdo_hpct_imported' ), + ); + + public function test_core_code_does_not_mention_hpct(): void { + $root = dirname( __DIR__, 2 ); + $offences = array(); + foreach ( array( 'includes', 'cli', 'admin' ) as $dir ) { + $files = new RecursiveIteratorIterator( new RecursiveDirectoryIterator( $root . '/' . $dir, FilesystemIterator::SKIP_DOTS ) ); + foreach ( $files as $file ) { + if ( 'php' !== $file->getExtension() ) { + continue; + } + $rel = substr( $file->getPathname(), strlen( $root ) + 1 ); + $code = ''; + foreach ( token_get_all( (string) file_get_contents( $file->getPathname() ) ) as $token ) { + if ( is_array( $token ) && in_array( $token[0], array( T_COMMENT, T_DOC_COMMENT ), true ) ) { + continue; + } + $code .= is_array( $token ) ? $token[1] : $token; + } + $code = str_replace( self::ALLOWED[ $rel ] ?? array(), '', $code ); + if ( preg_match_all( '/\w*hpct\w*/i', $code, $m ) ) { + $offences[] = $rel . ': ' . implode( ', ', array_unique( $m[0] ) ); + } + } + } + + $this->assertSame( array(), $offences, "HPCT legacy left in core:\n" . implode( "\n", $offences ) ); + } + + public function test_only_live_addon_modules_remain_besides_zone_modules(): void { + $this->assertSame( array( 'wc_orders', 'latepoint' ), TMDO_Feature_Flags::ADDON_MODULES ); + + $GLOBALS['_wp_options'] = array(); + $ref = new ReflectionProperty( TMDO_Feature_Flags::class, 'cache' ); + $ref->setAccessible( true ); + $ref->setValue( null, null ); + + $modules = array_keys( TMDO_Feature_Flags::all() ); + foreach ( array( 'reviews', 'messages', 'favorites', 'memberships', 'statistics', 'requests', 'listing_meta' ) as $gone ) { + $this->assertNotContains( $gone, $modules ); + } + } +}