diff --git a/includes/class-tmdo-comment-stress-tester.php b/includes/class-tmdo-comment-stress-tester.php index 65a35b9..f7cb248 100644 --- a/includes/class-tmdo-comment-stress-tester.php +++ b/includes/class-tmdo-comment-stress-tester.php @@ -492,7 +492,7 @@ final class TMDO_Comment_Stress_Tester { $state['completed_at'] = time(); update_option( self::OPT_STATE, $state, false ); if ( class_exists( 'TMDO_Logger' ) ) { - TMDO_Logger::error( 'comment_stress_test_batch_failed', array( 'message' => $e->getMessage() ) ); + TMDO_Logger::error( 'stress_test', 'comment_batch_failed', $e->getMessage() ); } return; } diff --git a/includes/class-tmdo-post-stress-tester.php b/includes/class-tmdo-post-stress-tester.php index 385ada5..982acb4 100644 --- a/includes/class-tmdo-post-stress-tester.php +++ b/includes/class-tmdo-post-stress-tester.php @@ -545,7 +545,7 @@ final class TMDO_Post_Stress_Tester { $state['completed_at'] = time(); update_option( self::OPT_STATE, $state, false ); if ( class_exists( 'TMDO_Logger' ) ) { - TMDO_Logger::error( 'post_stress_test_batch_failed', array( 'message' => $e->getMessage() ) ); + TMDO_Logger::error( 'stress_test', 'post_batch_failed', $e->getMessage() ); } return; } diff --git a/includes/class-tmdo-term-stress-tester.php b/includes/class-tmdo-term-stress-tester.php index 4b6c5d0..eb5852d 100644 --- a/includes/class-tmdo-term-stress-tester.php +++ b/includes/class-tmdo-term-stress-tester.php @@ -515,7 +515,7 @@ final class TMDO_Term_Stress_Tester { $state['completed_at'] = time(); update_option( self::OPT_STATE, $state, false ); if ( class_exists( 'TMDO_Logger' ) ) { - TMDO_Logger::error( 'term_stress_test_batch_failed', array( 'message' => $e->getMessage() ) ); + TMDO_Logger::error( 'stress_test', 'term_batch_failed', $e->getMessage() ); } return; } diff --git a/includes/class-tmdo-user-stress-tester.php b/includes/class-tmdo-user-stress-tester.php index c9f0156..9993e5b 100644 --- a/includes/class-tmdo-user-stress-tester.php +++ b/includes/class-tmdo-user-stress-tester.php @@ -403,7 +403,7 @@ final class TMDO_User_Stress_Tester { $state['completed_at'] = time(); update_option( self::OPT_STATE, $state, false ); if ( class_exists( 'TMDO_Logger' ) ) { - TMDO_Logger::error( 'stress_test_batch_failed', array( 'message' => $e->getMessage() ) ); + TMDO_Logger::error( 'stress_test', 'user_batch_failed', $e->getMessage() ); } return; } diff --git a/includes/engine/class-tmdo-auto-promoter.php b/includes/engine/class-tmdo-auto-promoter.php index c3a23e8..1971bbb 100644 --- a/includes/engine/class-tmdo-auto-promoter.php +++ b/includes/engine/class-tmdo-auto-promoter.php @@ -108,11 +108,10 @@ final class TMDO_Auto_Promoter { $result = TMDO_Mode_Manager::set( $type, TMDO_Mode_Manager::MODE_AEAV_ONLY ); if ( is_wp_error( $result ) ) { TMDO_Logger::error( + 'auto_promoter', 'auto_promote_failed', - array( - 'entity_type' => $type, - 'error' => $result->get_error_message(), - ) + $result->get_error_message(), + array( 'entity_type' => $type ) ); return 'error'; } diff --git a/includes/engine/class-tmdo-conflict-detector.php b/includes/engine/class-tmdo-conflict-detector.php index 74a70ec..0a13aba 100644 --- a/includes/engine/class-tmdo-conflict-detector.php +++ b/includes/engine/class-tmdo-conflict-detector.php @@ -76,11 +76,10 @@ final class TMDO_Conflict_Detector { if ( $conflicts ) { TMDO_Logger::error( + 'schema_registry', 'field_registration_conflict', - array( - 'count' => count( $conflicts ), - 'fields' => $conflicts, - ) + sprintf( 'Field registration conflict: %d field(s) affected', count( $conflicts ) ), + $conflicts ); } diff --git a/includes/engine/class-tmdo-hook-bus.php b/includes/engine/class-tmdo-hook-bus.php index 8638542..7d20802 100644 --- a/includes/engine/class-tmdo-hook-bus.php +++ b/includes/engine/class-tmdo-hook-bus.php @@ -418,12 +418,7 @@ final class TMDO_Hook_Bus { ); } catch ( \Throwable $e ) { // 比對失敗不該影響讀取 - TMDO_Logger::error( - 'shadow_compare_exception', - array( - 'error' => $e->getMessage(), - ) - ); + TMDO_Logger::error( 'entity_bridge', 'shadow_compare_exception', $e->getMessage() ); } } @@ -525,23 +520,39 @@ final class TMDO_Hook_Bus { $default = $field_def['default'] ?? null; if ( $delete_all ) { - // Safety cap: refuse mass-null if affected row count exceeds threshold. - // phpcs:ignore WordPress.DB.DirectDatabaseQuery,WordPress.DB.DirectDatabaseQuery.NoCaching,WordPress.DB.PreparedSQL.InterpolatedNotPrepared - $row_count = (int) $wpdb->get_var( "SELECT COUNT(*) FROM `{$table}`" ); + /** + * Opt-in gate for mass column clear (delete_all=true). + * + * Defaults to false — a single mistargetted call NULLs the column for + * every entity, and the previous row-count heuristic let small sites + * (< 500 rows) through unguarded. Enable only in controlled contexts: + * add_filter( 'wpdo_allow_mass_column_clear', '__return_true' ); + * + * @param bool $allow Whether to allow the mass clear. Default false. + * @param string $table Flat table name. + * @param string $col Column being cleared. + * @param string $meta_key Original meta key. + */ + $allowed = (bool) apply_filters( 'wpdo_allow_mass_column_clear', false, $table, $col, $meta_key ); + /** This filter is documented above (tmdo_* is the forward-looking name). */ + $allowed = (bool) apply_filters( 'tmdo_allow_mass_column_clear', $allowed, $table, $col, $meta_key ); - if ( $row_count > 500 ) { + if ( ! $allowed ) { TMDO_Logger::warning( 'intercept_delete_mass_blocked', array( - 'table' => $table, - 'col' => $col, - 'rows' => $row_count, + 'table' => $table, + 'col' => $col, + 'reason' => 'enable via wpdo_allow_mass_column_clear filter', ) ); return false; } - TMDO_Logger::info( + // phpcs:ignore WordPress.DB.DirectDatabaseQuery,WordPress.DB.DirectDatabaseQuery.NoCaching,WordPress.DB.PreparedSQL.InterpolatedNotPrepared + $row_count = (int) $wpdb->get_var( "SELECT COUNT(*) FROM `{$table}`" ); + + TMDO_Logger::warning( 'intercept_delete_all', array( 'table' => $table,