'break_detected', 'object_type' => 'anomaly', 'object_title' => __( 'Error spike detected', 'activitypilot' ), 'description' => sprintf( /* translators: 1: count, 2: minutes */ __( '%1$d errors detected within the last %2$d minutes.', 'activitypilot' ), $count, $window ), 'severity' => 'critical', 'context' => array( 'error_count' => $count, 'window_min' => $window, 'recent_changes' => $suspects, ), ) ); if ( ! empty( $settings['enable_alerts'] ) && ! empty( $settings['notify_email'] ) ) { self::send_alert_email( $settings['notify_email'], $count, $window, $suspects ); } } /** * Find recent high-impact changes that may have introduced the break. */ protected static function find_recent_changes( $window_min ) { $window = max( 1, (int) $window_min ); return APWPM_DB::get_break_suspects( $window ); } protected static function send_alert_email( $to, $count, $window, $suspects ) { $site = get_bloginfo( 'name' ); $subject = sprintf( /* translators: %s: site name */ __( '[%s] Activity Timeline: error spike detected', 'activitypilot' ), $site ); $body = sprintf( /* translators: 1: error count, 2: minute window, 3: site URL */ __( 'A spike of %1$d errors was detected within the last %2$d minutes on %3$s.', 'activitypilot' ), $count, $window, home_url() ); $body .= "\n\n" . __( 'Recent suspicious changes:', 'activitypilot' ) . "\n"; if ( empty( $suspects ) ) { $body .= '- ' . __( '(no recent high-impact changes found)', 'activitypilot' ) . "\n"; } else { foreach ( $suspects as $s ) { $body .= sprintf( "- [%s] %s on %s by %s\n", $s['created_at'], $s['action_type'], $s['object_title'], $s['user_login'] ); } } $body .= "\n" . __( 'Open the Activity Timeline dashboard:', 'activitypilot' ) . ' ' . admin_url( 'admin.php?page=apwpm-dashboard' ); wp_mail( $to, $subject, $body ); } }