admin_url( 'admin-ajax.php' ), 'nonce' => wp_create_nonce( 'cgard_run_scan' ), 'aiNonce' => wp_create_nonce( 'cgard_ai_action' ), 'i18n' => array( 'scanning' => __( 'Scanning…', 'clarityguard' ), 'error' => __( 'Scan failed. Please try again.', 'clarityguard' ), 'explaining' => __( 'Asking AI…', 'clarityguard' ), 'explainError' => __( 'Could not get an AI explanation. Check your API key under AI Settings.', 'clarityguard' ), 'generating' => __( 'Generating report…', 'clarityguard' ), 'reportError' => __( 'Could not generate the report. Check your API key under AI Settings.', 'clarityguard' ), ), ) ); } public function render_report_page() { if ( ! current_user_can( 'manage_options' ) ) { return; } // CGARD_Remediator only exists in the Freemius-hosted Pro package — // it's physically absent from the WordPress.org free package, not // merely disabled. This flag decides whether the report page can // show a *working* Auto-Fix button at all, independent of license // status (which still separately gates it in the Pro package). $has_pro_code = class_exists( 'CGARD_Remediator' ); $findings = CGARD_Db::get_findings( 'open' ); $last_scan = get_option( 'cgard_last_scan_time', '' ); $is_pro = CGARD_License::is_pro(); $revertible_fixes = ( $has_pro_code && $is_pro ) ? CGARD_Db::get_revertible_fixes( 10 ) : array(); $grouped = array( 'critical' => array(), 'high' => array(), 'medium' => array(), 'low' => array(), ); foreach ( $findings as $finding ) { $severity = isset( $grouped[ $finding['severity'] ] ) ? $finding['severity'] : 'low'; $grouped[ $severity ][] = $finding; } require CGARD_PLUGIN_DIR . 'admin/views/report-page.php'; } /** * AJAX handler for the manual "Run Scan Now" button. */ public function ajax_run_scan() { check_ajax_referer( 'cgard_run_scan', 'nonce' ); if ( ! current_user_can( 'manage_options' ) ) { wp_send_json_error( array( 'message' => __( 'Insufficient permissions.', 'clarityguard' ) ), 403 ); } $findings = CGARD_Scanner::run(); wp_send_json_success( array( 'count' => count( $findings ), ) ); } /** * AJAX handler for the per-finding "Explain with AI" button. */ public function ajax_explain_finding() { check_ajax_referer( 'cgard_ai_action', 'nonce' ); if ( ! current_user_can( 'manage_options' ) ) { wp_send_json_error( array( 'message' => __( 'Insufficient permissions.', 'clarityguard' ) ), 403 ); } $check_key = isset( $_POST['check_key'] ) ? sanitize_text_field( wp_unslash( $_POST['check_key'] ) ) : ''; $finding = $check_key ? CGARD_Db::get_finding_by_key( $check_key ) : null; if ( ! $finding ) { wp_send_json_error( array( 'message' => __( 'Finding not found — it may have been resolved since the page loaded.', 'clarityguard' ) ), 404 ); } $explainer = new CGARD_AI_Explainer(); $result = $explainer->explain_finding( $finding ); if ( is_wp_error( $result ) ) { wp_send_json_error( array( 'message' => $result->get_error_message() ) ); } wp_send_json_success( array( 'explanation' => $result ) ); } /** * AJAX handler for the "Generate AI Incident Report" button. */ public function ajax_generate_report() { check_ajax_referer( 'cgard_ai_action', 'nonce' ); if ( ! current_user_can( 'manage_options' ) ) { wp_send_json_error( array( 'message' => __( 'Insufficient permissions.', 'clarityguard' ) ), 403 ); } $findings = CGARD_Db::get_findings( 'open' ); $explainer = new CGARD_AI_Explainer(); $result = $explainer->generate_incident_report( $findings, get_bloginfo( 'name' ) ); if ( is_wp_error( $result ) ) { wp_send_json_error( array( 'message' => $result->get_error_message() ) ); } wp_send_json_success( array( 'report' => $result ) ); } }