diff --git a/admin/class-tmdo-admin.php b/admin/class-tmdo-admin.php index baa0540..27cae98 100644 --- a/admin/class-tmdo-admin.php +++ b/admin/class-tmdo-admin.php @@ -300,15 +300,15 @@ class TMDO_Admin { } // Handle rate limit stats reset. - if ( isset( $_GET['wpdo_reset_rl_stats'] ) && check_admin_referer( 'wpdo_reset_rl_stats' ) ) { + if ( isset( $_POST['wpdo_reset_rl_stats'] ) && check_admin_referer( 'wpdo_reset_rl_stats' ) ) { delete_option( 'wpdo_rl_stats' ); wp_safe_redirect( remove_query_arg( array( 'wpdo_reset_rl_stats', '_wpnonce' ) ) ); exit; } // v2.5.0 M16: one-click enable a module from suggestions tab. - if ( isset( $_GET['wpdo_enable_module'] ) && check_admin_referer( 'wpdo_enable_module' ) && TMDO_Capability::current_user_can_admin() ) { - $module = sanitize_key( wp_unslash( (string) $_GET['wpdo_enable_module'] ) ); + if ( isset( $_POST['wpdo_enable_module'] ) && check_admin_referer( 'wpdo_enable_module' ) && TMDO_Capability::current_user_can_admin() ) { + $module = sanitize_key( wp_unslash( (string) $_POST['wpdo_enable_module'] ) ); $flag = 'enable_failed'; if ( '' !== $module && class_exists( 'TMDO_Feature_Flags' ) ) { $result = TMDO_Feature_Flags::set( $module, 'dual_write' ); @@ -457,7 +457,7 @@ class TMDO_Admin { } // v2.3.0 M6: run health check on demand from Doctor tab. - if ( isset( $_GET['wpdo_run_health'] ) && check_admin_referer( 'wpdo_run_health' ) && class_exists( 'TMDO_Health_Cron' ) ) { + if ( isset( $_POST['wpdo_run_health'] ) && check_admin_referer( 'wpdo_run_health' ) && class_exists( 'TMDO_Health_Cron' ) ) { $res = TMDO_Health_Cron::run(); $flag = ( $res['critical_count'] ?? 0 ) > 0 ? 'health_critical' : 'health_ok'; wp_safe_redirect( @@ -473,7 +473,7 @@ class TMDO_Admin { } // v2.2.0 M4: snapshot create / delete admin actions. - if ( isset( $_GET['wpdo_create_snapshot'] ) && check_admin_referer( 'wpdo_create_snapshot' ) && class_exists( 'TMDO_Snapshot_Manager' ) ) { + if ( isset( $_POST['wpdo_create_snapshot'] ) && check_admin_referer( 'wpdo_create_snapshot' ) && class_exists( 'TMDO_Snapshot_Manager' ) ) { $result = TMDO_Snapshot_Manager::create( 'manual', array(), @@ -493,8 +493,8 @@ class TMDO_Admin { ); exit; } - if ( isset( $_GET['wpdo_delete_snapshot'] ) && check_admin_referer( 'wpdo_delete_snapshot' ) && class_exists( 'TMDO_Snapshot_Manager' ) ) { - $id = sanitize_text_field( wp_unslash( (string) $_GET['wpdo_delete_snapshot'] ) ); + if ( isset( $_POST['wpdo_delete_snapshot'] ) && check_admin_referer( 'wpdo_delete_snapshot' ) && class_exists( 'TMDO_Snapshot_Manager' ) ) { + $id = sanitize_text_field( wp_unslash( (string) $_POST['wpdo_delete_snapshot'] ) ); $ok = '' !== $id && TMDO_Snapshot_Manager::delete( $id ); wp_safe_redirect( add_query_arg( @@ -507,7 +507,7 @@ class TMDO_Admin { ); exit; } - if ( isset( $_GET['wpdo_prune_snapshots'] ) && check_admin_referer( 'wpdo_prune_snapshots' ) && class_exists( 'TMDO_Snapshot_Manager' ) ) { + if ( isset( $_POST['wpdo_prune_snapshots'] ) && check_admin_referer( 'wpdo_prune_snapshots' ) && class_exists( 'TMDO_Snapshot_Manager' ) ) { $res = TMDO_Snapshot_Manager::prune(); $msg = sprintf( 'pruned_%d', (int) ( $res['pruned'] ?? 0 ) ); wp_safe_redirect( @@ -523,7 +523,7 @@ class TMDO_Admin { } // v2.10.0: Post Migration Wizard — backfill all 7 groups. - if ( isset( $_GET['wpdo_post_backfill_all'] ) && check_admin_referer( 'wpdo_post_backfill_all' ) && class_exists( 'TMDO_Post_Migration' ) ) { + if ( isset( $_POST['wpdo_post_backfill_all'] ) && check_admin_referer( 'wpdo_post_backfill_all' ) && class_exists( 'TMDO_Post_Migration' ) ) { $total_migrated = 0; $errors = array(); foreach ( array( 'wp_core', 'attachment', 'wc_product', 'hp_listing_core', 'hp_request_core', 'hp_vendor_core', 'nav_menu_item' ) as $group ) { @@ -557,7 +557,7 @@ class TMDO_Admin { } // v2.10.0: Post Migration Wizard — copy legacy hot table. - if ( isset( $_GET['wpdo_post_cutover_legacy'] ) && check_admin_referer( 'wpdo_post_cutover_legacy' ) && class_exists( 'TMDO_Post_Migration' ) ) { + if ( isset( $_POST['wpdo_post_cutover_legacy'] ) && check_admin_referer( 'wpdo_post_cutover_legacy' ) && class_exists( 'TMDO_Post_Migration' ) ) { global $wpdb; $hot = $wpdb->prefix . 'wpdo_hot_hp_listing'; $flat = $wpdb->prefix . 'wpdo_post_hp_listing_core'; @@ -596,9 +596,9 @@ class TMDO_Admin { } // v2.10.0: Post Migration Wizard — promote mode (dual_write or aeav_only). - if ( ( isset( $_GET['wpdo_post_promote_dual_write'] ) || isset( $_GET['wpdo_post_promote_aeav'] ) ) && class_exists( 'TMDO_Post_Migration' ) ) { - $target = isset( $_GET['wpdo_post_promote_dual_write'] ) ? 'dual_write' : 'aeav_only'; - $nonce = isset( $_GET['wpdo_post_promote_dual_write'] ) ? 'wpdo_post_promote_dual_write' : 'wpdo_post_promote_aeav'; + if ( ( isset( $_POST['wpdo_post_promote_dual_write'] ) || isset( $_POST['wpdo_post_promote_aeav'] ) ) && class_exists( 'TMDO_Post_Migration' ) ) { + $target = isset( $_POST['wpdo_post_promote_dual_write'] ) ? 'dual_write' : 'aeav_only'; + $nonce = isset( $_POST['wpdo_post_promote_dual_write'] ) ? 'wpdo_post_promote_dual_write' : 'wpdo_post_promote_aeav'; if ( check_admin_referer( $nonce ) ) { $result = TMDO_Post_Migration::set_mode( $target ); $err = is_wp_error( $result ) ? $result->get_error_message() : ''; @@ -627,10 +627,10 @@ class TMDO_Admin { // v2.11.0: Post Stress Test — bulk create test posts. // v2.11.2: optional `mode` query arg (fast|realistic). - if ( isset( $_GET['wpdo_post_stress_create'] ) && check_admin_referer( 'wpdo_post_stress_create' ) && class_exists( 'TMDO_Post_Stress_Tester' ) ) { - $post_type = isset( $_GET['post_type'] ) ? sanitize_key( wp_unslash( (string) $_GET['post_type'] ) ) : 'product'; - $count = isset( $_GET['count'] ) ? max( 1, min( 10000, absint( wp_unslash( $_GET['count'] ) ) ) ) : 100; - $mode = isset( $_GET['mode'] ) && 'realistic' === sanitize_key( wp_unslash( (string) $_GET['mode'] ) ) ? 'realistic' : 'fast'; + if ( isset( $_POST['wpdo_post_stress_create'] ) && check_admin_referer( 'wpdo_post_stress_create' ) && class_exists( 'TMDO_Post_Stress_Tester' ) ) { + $post_type = isset( $_POST['post_type'] ) ? sanitize_key( wp_unslash( (string) $_POST['post_type'] ) ) : 'product'; + $count = isset( $_POST['count'] ) ? max( 1, min( 10000, absint( wp_unslash( $_POST['count'] ) ) ) ) : 100; + $mode = isset( $_POST['mode'] ) && 'realistic' === sanitize_key( wp_unslash( (string) $_POST['mode'] ) ) ? 'realistic' : 'fast'; try { $result = 'realistic' === $mode ? TMDO_Post_Stress_Tester::create_realistic( $post_type, $count ) @@ -655,7 +655,7 @@ class TMDO_Admin { } // v2.11.0: Post Stress Test — cleanup all test posts. - if ( isset( $_GET['wpdo_post_stress_cleanup'] ) && check_admin_referer( 'wpdo_post_stress_cleanup' ) && class_exists( 'TMDO_Post_Stress_Tester' ) ) { + if ( isset( $_POST['wpdo_post_stress_cleanup'] ) && check_admin_referer( 'wpdo_post_stress_cleanup' ) && class_exists( 'TMDO_Post_Stress_Tester' ) ) { try { $result = TMDO_Post_Stress_Tester::cleanup(); $msg = 'stress_cleanup_' . (int) $result['deleted_posts']; @@ -678,8 +678,8 @@ class TMDO_Admin { } // v2.11.0: Post Stress Test — run benchmark on all 7 groups. - if ( isset( $_GET['wpdo_post_stress_bench'] ) && check_admin_referer( 'wpdo_post_stress_bench' ) && class_exists( 'TMDO_Post_Migration' ) ) { - $samples = isset( $_GET['samples'] ) ? max( 10, min( 1000, absint( wp_unslash( $_GET['samples'] ) ) ) ) : 100; + if ( isset( $_POST['wpdo_post_stress_bench'] ) && check_admin_referer( 'wpdo_post_stress_bench' ) && class_exists( 'TMDO_Post_Migration' ) ) { + $samples = isset( $_POST['samples'] ) ? max( 10, min( 1000, absint( wp_unslash( $_POST['samples'] ) ) ) ) : 100; set_transient( 'wpdo_post_stress_bench_samples', $samples, 60 ); $msg = 'stress_bench_ready_' . $samples; wp_safe_redirect( @@ -695,7 +695,7 @@ class TMDO_Admin { } // v2.9.0 Phase 0: wp_postmeta garbage cleanup (transients/_wp_old_date/stale _edit_lock). - if ( isset( $_GET['wpdo_postmeta_cleanup'] ) && check_admin_referer( 'wpdo_postmeta_cleanup' ) && class_exists( 'TMDO_Postmeta_Cleaner' ) ) { + if ( isset( $_POST['wpdo_postmeta_cleanup'] ) && check_admin_referer( 'wpdo_postmeta_cleanup' ) && class_exists( 'TMDO_Postmeta_Cleaner' ) ) { $deleted = TMDO_Postmeta_Cleaner::delete_garbage( TMDO_Postmeta_Cleaner::TARGET_ALL ); if ( class_exists( 'TMDO_Logger' ) ) { TMDO_Logger::info( @@ -1261,21 +1261,11 @@ class TMDO_Admin {

0 ) : ?> - +

+ + + +

@@ -2849,15 +2839,17 @@ wpdo.getListings({ per_page: 3 }).then(r => console.log(r));'

- - - - - - +
+ + + + +
+ + + +

@@ -2887,11 +2879,12 @@ wpdo.getListings({ per_page: 3 }).then(r => console.log(r));' @@ -3109,10 +3102,6 @@ wpdo.getListings({ per_page: 3 }).then(r => console.log(r));' $conf = (float) $r['confidence']; $bar_w = (int) round( $conf * 100 ); $color = $conf >= 0.7 ? '#46b450' : ( $conf >= 0.5 ? '#dba617' : '#c3c4c7' ); - $enable_url = wp_nonce_url( - add_query_arg( 'wpdo_enable_module', $module, admin_url( 'tools.php?page=' . self::MENU_SLUG ) ), - 'wpdo_enable_module' - ); printf( '', esc_html( $module ), @@ -3129,12 +3118,15 @@ wpdo.getListings({ per_page: 3 }).then(r => console.log(r));' } echo ''; printf( '', esc_html( (string) $r['current_state'] ) ); + echo '', - esc_url( $enable_url ), + '', esc_js( __( '確定啟用此 module(推進到 dual_write)?', '2meet-data-optimizer' ) ), esc_html__( '✅ 啟用', '2meet-data-optimizer' ) ); + echo ''; echo ''; } echo '
- - - +
+ + + +
%s
%s
%s
'; + printf( '', esc_attr( $module ) ); + wp_nonce_field( 'wpdo_enable_module' ); printf( - '
%s
'; diff --git a/admin/class-tmdo-dashboard-widget.php b/admin/class-tmdo-dashboard-widget.php index d16ebaf..577199a 100644 --- a/admin/class-tmdo-dashboard-widget.php +++ b/admin/class-tmdo-dashboard-widget.php @@ -59,9 +59,7 @@ class TMDO_Dashboard_Widget { */ public static function render(): void { $page_url = admin_url( 'tools.php?page=wp-data-optimizer' ); - $run_health_url = wp_nonce_url( add_query_arg( array( 'wpdo_run_health' => '1' ), $page_url ), 'wpdo_run_health' ); - $create_snap_url = wp_nonce_url( add_query_arg( array( 'wpdo_create_snapshot' => '1' ), $page_url ), 'wpdo_create_snapshot' ); - $bridge_url = add_query_arg( 'tab', 'entity-bridge', $page_url ); + $bridge_url = add_query_arg( 'tab', 'entity-bridge', $page_url ); $status = self::compute_status(); $light = self::traffic_light( $status['level'] ); @@ -188,10 +186,6 @@ class TMDO_Dashboard_Widget { ? TMDO_Postmeta_Cleaner::count_garbage( TMDO_Postmeta_Cleaner::TARGET_ALL ) : array( 'total' => 0 ); if ( ! empty( $gc['total'] ) && (int) $gc['total'] > 0 ) : - $cleanup_url = wp_nonce_url( - add_query_arg( array( 'wpdo_postmeta_cleanup' => '1' ), $page_url ), - 'wpdo_postmeta_cleanup' - ); $confirm_msg = sprintf( /* translators: %s: total garbage row count */ esc_html__( '即將從 wp_postmeta 刪除 %s 行垃圾資料(transients + _wp_old_date + 過期 _edit_lock)。確認執行?', '2meet-data-optimizer' ), @@ -211,10 +205,14 @@ class TMDO_Dashboard_Widget { esc_html( number_format_i18n( (int) $gc['edit_locks'] ) ) ); ?> - - - +
+ + + +

@@ -275,15 +273,19 @@ class TMDO_Dashboard_Widget {
- - - +
+ + + +
- - - +
+ + + +
diff --git a/admin/class-tmdo-setup-wizard.php b/admin/class-tmdo-setup-wizard.php index 30243cb..f468219 100644 --- a/admin/class-tmdo-setup-wizard.php +++ b/admin/class-tmdo-setup-wizard.php @@ -343,15 +343,18 @@ class TMDO_Setup_Wizard {

-

- - - -

+
+ + +

+ +

+
__( '🟢 aeav_only — flat 表為 source-of-truth', '2meet-data-optimizer' ), ); -// Action URLs (each carries nonce). -$cleanup_garbage_url = wp_nonce_url( - add_query_arg( array( 'wpdo_postmeta_cleanup' => '1' ), $page_url ), - 'wpdo_postmeta_cleanup' -); -$backfill_all_url = wp_nonce_url( - add_query_arg( array( 'wpdo_post_backfill_all' => '1' ), $page_url ), - 'wpdo_post_backfill_all' -); -$cutover_legacy_url = wp_nonce_url( - add_query_arg( array( 'wpdo_post_cutover_legacy' => '1' ), $page_url ), - 'wpdo_post_cutover_legacy' -); -$promote_dual_write_url = wp_nonce_url( - add_query_arg( array( 'wpdo_post_promote_dual_write' => '1' ), $page_url ), - 'wpdo_post_promote_dual_write' -); -$promote_aeav_url = wp_nonce_url( - add_query_arg( array( 'wpdo_post_promote_aeav' => '1' ), $page_url ), - 'wpdo_post_promote_aeav' -); // Status banner from prior action redirect. // Read-only display banner — server-set redirect message, no form processing. @@ -234,11 +213,14 @@ $wpdo_format_msg = static function ( string $code ): string { ?>

- - - +
+ + + +
@@ -246,10 +228,14 @@ $wpdo_format_msg = static function ( string $code ): string {

- - - +
+ + + +
@@ -257,10 +243,14 @@ $wpdo_format_msg = static function ( string $code ): string {

- - - +
+ + + +
@@ -268,10 +258,14 @@ $wpdo_format_msg = static function ( string $code ): string {

- - - +
+ + + +
@@ -279,10 +273,14 @@ $wpdo_format_msg = static function ( string $code ): string {

- - - +
+ + + +
diff --git a/admin/templates/post-stress-test.php b/admin/templates/post-stress-test.php index 1ef71be..f61206a 100644 --- a/admin/templates/post-stress-test.php +++ b/admin/templates/post-stress-test.php @@ -7,8 +7,7 @@ * 2. 即時進度(progress bar + processed/target/rate/ETA/peak memory) * 3. Benchmark 報告(write metrics + DB sizes + query performance) * - * Backward-compat: legacy GET ?wpdo_post_stress_create / cleanup / bench - * handlers in admin still work for bookmarked URLs; the new UI uses REST. + * The UI uses REST/AJAX exclusively; legacy admin action handlers now require POST. * * Variables in scope from render_post_stress_test(): * $test_post_count — int, posts matching TMDO_STRESS_TEST_ prefix @@ -23,11 +22,6 @@ if ( ! defined( 'ABSPATH' ) ) { $page_url = admin_url( 'tools.php?page=wp-data-optimizer&tab=post-stress-test' ); -$cleanup_url = wp_nonce_url( - add_query_arg( array( 'wpdo_post_stress_cleanup' => '1' ), $page_url ), - 'wpdo_post_stress_cleanup' -); - // Read-only display banner — server-set redirect message, no form processing. // phpcs:ignore WordPress.Security.NonceVerification.Recommended $msg_raw = isset( $_GET['wpdo_msg'] ) ? sanitize_text_field( wp_unslash( (string) $_GET['wpdo_msg'] ) ) : '';