> $schedules Cron schedules. * @return array> */ public function add_cron_schedules( array $schedules ): array { if ( ! isset( $schedules['weekly'] ) ) { $schedules['weekly'] = array( 'interval' => WEEK_IN_SECONDS, 'display' => esc_html__( 'Once Weekly', 'ability-guard' ), ); } return $schedules; } /** * Send an alert after a log insert if a rule matches. * * @param int $log_id Log ID. * @param array $data Log data. */ public function maybe_send_alert( int $log_id, array $data ): void { if ( ! (bool) get_option( 'ability_guard_alerts_enabled', false ) ) { return; } $reasons = array(); $ability_name = isset( $data['ability_name'] ) ? (string) $data['ability_name'] : ''; $status = isset( $data['status'] ) ? sanitize_key( (string) $data['status'] ) : ''; $watchlist = get_option( 'ability_guard_watchlist', array() ); $watchlist = is_array( $watchlist ) ? $watchlist : array(); if ( (bool) get_option( 'ability_guard_alert_on_errors', true ) && 'error' === $status ) { $reasons[] = __( 'the execution failed', 'ability-guard' ); } if ( (bool) get_option( 'ability_guard_alert_on_watched', true ) && in_array( $ability_name, $watchlist, true ) ) { $reasons[] = __( 'the ability is on your sensitive watchlist', 'ability-guard' ); } if ( (bool) get_option( 'ability_guard_alert_on_high_risk', true ) && 'high' === $this->get_ability_risk( $ability_name ) ) { $reasons[] = __( 'the ability is marked high risk', 'ability-guard' ); } if ( empty( $reasons ) ) { return; } $email = sanitize_email( (string) get_option( 'ability_guard_alert_email', get_option( 'admin_email' ) ) ); if ( '' === $email ) { return; } $subject = sprintf( /* translators: %s: ability name. */ __( 'AbilityGuard alert: %s', 'ability-guard' ), $ability_name ); $message = sprintf( /* translators: 1: ability name, 2: reasons, 3: status, 4: log URL. */ __( "AbilityGuard detected monitored ability activity.\n\nAbility: %1\$s\nReason: %2\$s\nStatus: %3\$s\nLog details: %4\$s", 'ability-guard' ), $ability_name, implode( ', ', $reasons ), $status, admin_url( 'admin.php?page=ability-guard-logs&log_id=' . absint( $log_id ) ) ); wp_mail( $email, $subject, $message ); } /** * Send scheduled report. */ public function send_scheduled_report(): void { if ( ! (bool) get_option( 'ability_guard_reports_enabled', false ) ) { return; } $email = sanitize_email( (string) get_option( 'ability_guard_report_email', get_option( 'admin_email' ) ) ); if ( '' === $email ) { return; } $frequency = (string) get_option( 'ability_guard_report_frequency', 'weekly' ); $days = 'daily' === $frequency ? 1 : 7; $from = gmdate( 'Y-m-d', time() - ( $days * DAY_IN_SECONDS ) ); $repository = new Ability_Guard_Log_Repository(); $total = $repository->count_logs( array( 'date_from' => $from ) ); $errors = $repository->count_logs( array( 'date_from' => $from, 'status' => 'error', ) ); $logs = $repository->get_logs( array( 'date_from' => $from, 'per_page' => 10, 'page' => 1, ) ); $lines = array( sprintf( /* translators: %d: number of days. */ __( 'AbilityGuard activity report for the last %d day(s).', 'ability-guard' ), $days ), '', sprintf( /* translators: %d: total logs. */ __( 'Total executions: %d', 'ability-guard' ), $total ), sprintf( /* translators: %d: error logs. */ __( 'Failed executions: %d', 'ability-guard' ), $errors ), '', __( 'Recent activity:', 'ability-guard' ), ); foreach ( $logs as $log ) { $lines[] = sprintf( '%s | %s | %s | %s', $log->created_at, $log->ability_name, $log->triggered_via, $log->status ); } $lines[] = ''; $lines[] = admin_url( 'admin.php?page=ability-guard-logs' ); wp_mail( $email, __( 'AbilityGuard activity report', 'ability-guard' ), implode( "\n", $lines ) ); } /** * Get normalized ability risk by name. * * @param string $ability_name Ability name. * @return string */ private function get_ability_risk( string $ability_name ): string { $scanner = new Ability_Guard_Ability_Scanner(); $ability = $scanner->get_ability( $ability_name ); return $ability && isset( $ability['risk'] ) ? (string) $ability['risk'] : 'unknown'; } }