= 0 && $value <= 1000000000 ? $value : null; } /** Pure scan projection, shared by rendering and state qualification. */ public static function snapshot( ?array $scan, int $outstanding = 0 ): array { $status = is_string( $scan['_status'] ?? null ) ? $scan['_status'] : 'not_started'; $active = in_array( $status, array( 'queued', 'running' ), true ); $targeted = ! empty( $scan['target_finding_id'] ) || 'targeted' === ( $scan['mode'] ?? '' ); $counters = is_array( $scan['counters'] ?? null ) ? $scan['counters'] : array(); $skipped = self::number( $counters['skipped'] ?? null ); $unreadable = self::number( $counters['unreadable'] ?? null ); $gaps = null !== $skipped && null !== $unreadable ? $skipped + $unreadable : null; $observed = self::number( $counters['findings'] ?? null ); $countsAvailable = null !== $gaps && null !== $observed && null !== self::number( $counters['checked'] ?? null ) && null !== self::number( $counters['database_checked'] ?? null ); $incomplete = $scan && ( ! $countsAvailable || ! in_array( $status, array( 'completed', 'queued', 'running' ), true ) || 'scan_incomplete' === ( $scan['result_state'] ?? '' ) || $gaps > 0 || ! empty( $scan['coverage']['local_engine']['incomplete'] ) ); $confirmed = 'confirmed_threat' === ( $scan['result_state'] ?? '' ); if ( ! $scan ) { $summary = 'Run your first scan to see what needs attention and what could be checked.'; } elseif ( $active ) { $summary = 'Your scan is still running. Review progress below; the final result is not ready yet.'; } elseif ( $confirmed ) { $summary = 'The scan recorded a confirmed threat finding. Review it next and decide how to respond. No repair has been approved by the scan.'; } elseif ( ! $countsAvailable ) { $summary = 'Required scan counts are unavailable. Review the saved evidence and run another scan before relying on this result.'; } elseif ( $incomplete ) { $summary = 'Some checks could not finish. Review what was missed and any findings before relying on this result.'; } elseif ( 'no_threats_detected' === ( $scan['result_state'] ?? '' ) ) { $summary = 'No threats were detected in the completed checks. Review what was excluded or unavailable; this is not a guarantee that the whole site is clean.'; } elseif ( 'attention_needed' === ( $scan['result_state'] ?? '' ) ) { $summary = 'There are findings to review. A changed file or vulnerable version does not, by itself, mean the site is infected.'; } else { $summary = 'The saved scan result could not be understood. Review its details before relying on it.'; } if ( $targeted ) { $summary .= ' This check covers only the selected finding, not the whole site.'; } $coverage = ! $scan ? 'Not scanned yet' : ( $incomplete ? 'Some checks were missed' : ( $active ? 'Checks are still running' : ( $targeted ? 'One finding checked' : 'What this scan covered' ) ) ); $detail = $scan && ! $countsAvailable ? 'Required scan counts are unavailable; missing values do not mean zero.' : ( $gaps ? sprintf( '%d skipped or unreadable items remain unassessed.', $gaps ) : 'Review excluded items, unsupported content and any unavailable checks.' ); return array( 'summary' => $summary, 'coverage' => $coverage, 'coverage_detail' => $detail, 'active' => $active, 'incomplete' => (bool) $incomplete, 'targeted' => $targeted, 'confirmed' => $confirmed, 'observed' => $observed, 'outstanding' => max( 0, $outstanding ), 'gaps' => $gaps, 'counters_available' => $countsAvailable ); } /** Fetch high-severity unresolved evidence first; each query and returned set is bounded. */ public static function focus( Store $store ): array { $items = array(); foreach ( array( 'critical', 'high', 'medium', 'low', 'info' ) as $severity ) { foreach ( array( 'open', 'acknowledged' ) as $status ) { $result = $store->searchFindings( array( 'severity' => $severity, 'status' => $status ), 3 ); foreach ( $result['items'] as $finding ) { if ( '' !== FindingGuide::id( $finding ) ) { $items[ $finding['_id'] ] = $finding; } } } if ( count( $items ) >= 3 ) { break; } } $items = array_values( $items ); usort( $items, static function ( $a, $b ) { $levels = array( 'critical' => 5, 'high' => 4, 'medium' => 3, 'low' => 2, 'info' => 1 ); $severity = ( $levels[ $b['severity'] ?? '' ] ?? 0 ) <=> ( $levels[ $a['severity'] ?? '' ] ?? 0 ); if ( $severity ) { return $severity; } $confidence = array( 'confirmed' => 4, 'strong' => 3, 'suspicious' => 2, 'informational' => 1 ); return ( $confidence[ $b['confidence'] ?? '' ] ?? 0 ) <=> ( $confidence[ $a['confidence'] ?? '' ] ?? 0 ); } ); return array_slice( $items, 0, 3 ); } private static function action( string $operation, string $label, string $id = '', string $style = 'primary' ): void { Admin::formStart( $operation ); if ( '' !== $id ) { echo ''; } submit_button( $label, $style, 'submit', false ); echo ''; } public static function render( Store $store, ?array $scan, array $state, array $history ): void { $count = $store->count( 'finding', 'open' ) + $store->count( 'finding', 'acknowledged' ); $brief = self::snapshot( $scan, $count ); $focus = self::focus( $store ); $at = $scan['completed_at'] ?? $scan['updated_at'] ?? $scan['started_at'] ?? ''; $at = is_string( $at ) ? $at : ''; echo '
' . esc_html__( 'Saved scan result', 'shieldlume-security' ) . '' . esc_html( $at ? ( ! empty( $scan['completed_at'] ) ? 'Scan finished · ' : 'Scan updated · ' ) . $at : 'No scan recorded' ) . '
' . esc_html( $state['label'] ) . '

' . esc_html( $state['heading'] ) . '

' . esc_html( $brief['summary'] ) . '

'; if ( $brief['targeted'] ) { echo '

' . esc_html__( 'Last completed broad scan:', 'shieldlume-security' ) . ' ' . esc_html( $history['last_successful']['completed_at'] ?? 'Not recorded' ) . '

'; } echo '
'; if ( $brief['active'] ) { self::action( 'tick', __( 'Continue scanning', 'shieldlume-security' ), $scan['_id'] ); self::action( 'cancel', __( 'Stop scan', 'shieldlume-security' ), $scan['_id'], 'secondary' ); } else { if ( $count ) { echo '' . esc_html__( 'Review findings', 'shieldlume-security' ) . ''; } self::action( 'scan', $scan ? __( 'Run a new scan', 'shieldlume-security' ) : __( 'Run your first scan', 'shieldlume-security' ), '', $count ? 'secondary' : 'primary' ); } echo '

' . esc_html( $brief['active'] ? 'Refresh to see saved progress, or choose Continue scanning to process the next part.' : 'Opening this page does not change your files.' ) . '

'; echo '
' . esc_html( $brief['coverage'] ) . '

' . esc_html( $brief['coverage_detail'] ) . '

' . esc_html__( 'See what was checked', 'shieldlume-security' ) . '

' . esc_html__( 'What needs your attention', 'shieldlume-security' ) . '

' . esc_html( sprintf( '%d open or acknowledged findings across retained scans', $count ) ) . '
'; if ( $focus ) { echo '
    '; foreach ( $focus as $finding ) { $guide = FindingGuide::describe( $finding ); echo '
  1. ' . esc_html( str_replace( '_', ' ', $finding['category'] ?? 'observation' ) ) . ' · ' . esc_html( $finding['severity'] ?? 'info' ) . '

    ' . esc_html( $guide['title'] ) . '

    ' . esc_html( $guide['why'] ) . '

    ' . esc_html__( 'Observed:', 'shieldlume-security' ) . ' ' . esc_html( is_string( $finding['observed_at'] ?? null ) ? $finding['observed_at'] : 'Time not recorded' ) . '
    ' . esc_html__( 'Review next step', 'shieldlume-security' ) . '
  2. '; } echo '
' . esc_html__( 'How findings are ordered', 'shieldlume-security' ) . '

' . esc_html__( 'Higher recorded severity comes first; evidence strength breaks ties among the recent records retrieved. This is a review order, not an infection probability. Findings from earlier scans remain visible until reviewed.', 'shieldlume-security' ) . '

'; } else { echo '

' . esc_html( $count ? 'These findings could not be shown here. Open Findings to review the saved records.' : 'No findings are waiting for review. Check the scan coverage above before relying on the result.' ) . '

'; } $items = ProtectionChecklist::items( $store, $scan ); echo '
'; $shown = 0; foreach ( $items as $item ) { if ( in_array( $item['title'], array( 'Review open findings', 'Establish scan coverage' ), true ) || 'Keep detection sources current' === $item['title'] ) { continue; } if ( $shown++ >= 2 ) { break; } echo '

' . esc_html( $item['title'] ) . '

' . esc_html( $item['copy'] ) . '

' . esc_html( $item['action'] ) . '
'; } echo '
'; foreach ( $items as $item ) { if ( 'Keep detection sources current' !== $item['title'] ) { continue; } echo '
' . esc_html__( 'Detection sources:', 'shieldlume-security' ) . ' ' . esc_html( $item['state'] ) . '

' . esc_html( $item['copy'] ) . '

' . esc_html__( 'Inspect source freshness & coverage', 'shieldlume-security' ) . '
'; } echo '

' . esc_html__( 'Optional Pro file repairs need a preview, your approval and verification of the result.', 'shieldlume-security' ) . '

'; } }